DFU分析

最近因为项目的原因看了下DFU的资料,也下个Demo来研究了下,其实也就是在USB驱动中嵌入DFU驱动而已,弄明白了DFU的协议,就很容易了。DFU有个specification,全名叫USB Device Class Specification for Device Firmware Upgrade。可见其和USB之间的密切关系。

当把DFU嵌入USB后,系统运行状态一般就可以分为二种模式,一种是就是正常的USB运行模式,一种是DFU模式,二种模式不能共存。那如果确定是哪种模式呢,这就要通过寻找DFU class interface descriptor来判断设备是否具有DFU功能,也就是升级固件的功能。而这个DFU class interface descriptor和USB中interface中的interface descriptor结构是一样的,的在DFU Specification中提到其interface descriptor中的bInterfaceClass为EFh,而其bInterfaceSubClass为01h,这就是我们判断的依据。
if (intf->bInterfaceClass == 0xfe &&  intf->bInterfaceSubClass == 1)
{
             ......
}
这里需要注意的是,在正常的模式下,只有一个DFU Class interface descriptor.同时在bInterfaceProtocol为01的话就代表还是在正常模式,为02在处于DFU协议下了。

如果有多个设备具有DFU功能,这时就要注意了,因为在 DFU Specification中提到,其协议只支持一个具有DFU功能的设备,原因是在从正常模式下进入DFU模式前必须reset总线。具有DFU功能的设备地址将会改变。

发送dfu_detach后,还重新re-scan USB。这里的dfu_detach是DFU Specification中定义的请求,如果函数成功则可以在reset usb后进入DFU模式,下面是发送DFU的代码,利用usblib这个库,也就是我在上一篇提到的。

usb_control_msg( device,
        /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
        /* bRequest      */ DFU_DETACH,
        /* wValue        */ timeout,
        /* wIndex        */ interface,
        /* Data          */ NULL,
        /* wLength       */ 0,
                            dfu_timeout );

在DFU Specification中提到DFU有很多状态,在各个状态实现不同的功能,比如在 DFU_STATE_dfuERROR状态下只能调用dfu_clear_status才能回到dfuIdle模式下,Demo中的代码如下:

status_again:
               printf("Determining device status: ");
               if (dfu_get_status(dif->dev_handle, dif->interface, &status ) < 0) {
                        fprintf(stderr, "error get_status: %s/n", usb_strerror());
                       exit(1);
               } 
switch (status.bState) {
               case DFU_STATE_appIDLE:
               case DFU_STATE_appDETACH:
                        fprintf(stderr, "Device still in Runtime Mode!/n");
                        exit(1);
                        break;
               case DFU_STATE_dfuERROR:
                        printf("dfuERROR, clearing status/n");
                        if (dfu_clear_status(dif->dev_handle, dif->interface) < 0) {
                                 fprintf(stderr, "error clear_status: %s/n", usb_strerror());
                                 exit(1);
                        }
                       goto status_again;
                       break;
                case DFU_STATE_dfuDNLOAD_IDLE:
                case DFU_STATE_dfuUPLOAD_IDLE:
                       printf("aborting previous incomplete transfer/n");
                       if (dfu_abort(dif->dev_handle, dif->interface) < 0) {
                               fprintf(stderr, "can't send DFU_ABORT: %s/n", usb_strerror());
                               exit(1);
                        }
                       goto status_again;
                       break;
                case DFU_STATE_dfuIDLE:
                       printf("dfuIDLE, continuing/n");
                       break;

}

其中的dfu_get_status等都是调用usb_control_msg来实现的。

然后可以执行下载,上传的操作了。同样调用usb_control_msg来实现,比如对于更新固件,就可以
    status = usb_control_msg( device,
          /* bmRequestType */ USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
          /* bRequest      */ DFU_UPLOAD,
          /* wValue        */ transaction++,
          /* wIndex        */ interface,
          /* Data          */ data,
          /* wLength       */ length,
                              dfu_timeout );

 

你可能感兴趣的:(upload,null,Class,interface,Descriptor)