Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wish the OpenCM9.04 had a more complete USB descriptor #21

Closed
KurtE opened this issue Mar 27, 2018 · 14 comments
Closed

Wish the OpenCM9.04 had a more complete USB descriptor #21

KurtE opened this issue Mar 27, 2018 · 14 comments
Assignees
Labels

Comments

@KurtE
Copy link
Contributor

KurtE commented Mar 27, 2018

As the title mentions, I wish the descriptor was more complete, some of it may simply be cosmetic, like maybe having string objects to give the company name and product name... But part of it is also functional information. For example does each OpenCM9.04 have a Serial number?

My guess is currently not or at least not accessible as part of the USB information. Why is this maybe important. Unlike other Arduino devices, that I plug into my computer, all of the OpenCM boards all try to use the same COM port number on Windows. I Have not checked on a MAC, but guessing probably the same.

Example comparing the information that Linux knows about the device:

  dmesg | tail
  [  187.801982] usb 1-3: new full-speed USB device number 8 using xhci_hcd
  [  187.931238] usb 1-3: New USB device found, idVendor=fff1, idProduct=ff48
  [  187.931246] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
  [  187.931250] usb 1-3: Product: ROBOTIS Virtual COM Port
  [  187.931253] usb 1-3: Manufacturer: CM-900
  [  187.931564] usb 1-3: ep 0x82 - rounding interval to 1024 microframes, ep desc says 2040 microframes
  [  187.972767] cdc_acm 1-3:1.0: ttyACM0: USB ACM device
  [  187.973957] usbcore: registered new interface driver cdc_acm
  [  187.974013] cdc_acm: USB Abstract Control Model driver for USB modems and 

  kurt@kurt-UP-Turtle:~$ lsusb
  Bus 002 Device 002: ID 8086:0a80 Intel Corp.
  Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
  Bus 001 Device 007: ID 0424:2530 Standard Microsystems Corp.
  Bus 001 Device 006: ID 0424:4603 Standard Microsystems Corp.
  Bus 001 Device 008: ID fff1:ff48
  Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

  kurt@kurt-UP-Turtle:~$ lsusb -v -d  fff1:ff48

  Bus 001 Device 008: ID fff1:ff48
  Device Descriptor:
    bLength                18
    bDescriptorType         1
    bcdUSB               2.00
    bDeviceClass            2 Communications
    bDeviceSubClass         0
    bDeviceProtocol         0
    bMaxPacketSize0        64
    idVendor           0xfff1
    idProduct          0xff48
    bcdDevice            2.00
    iManufacturer           1 (error)
    iProduct                2 (error)
    iSerial                 0
    bNumConfigurations      1
    Configuration Descriptor:
      bLength                 9
      bDescriptorType         2
      wTotalLength           67
      bNumInterfaces          2
      bConfigurationValue     1
      iConfiguration          0
      bmAttributes         0x80
        (Bus Powered)
      MaxPower                0mA
      Interface Descriptor:
        bLength                 9
        bDescriptorType         4
        bInterfaceNumber        0
        bAlternateSetting       0
        bNumEndpoints           1
        bInterfaceClass         2 Communications
        bInterfaceSubClass      2 Abstract (modem)
        bInterfaceProtocol      1 AT-commands (v.25ter)
        iInterface              0
        CDC Header:
          bcdCDC               1.10
        CDC Call Management:
          bmCapabilities       0x00
          bDataInterface          1
        CDC ACM:
          bmCapabilities       0x02
            line coding and serial state
        CDC Union:
          bMasterInterface        0
          bSlaveInterface         1
        Endpoint Descriptor:
          bLength                 7
          bDescriptorType         5
          bEndpointAddress     0x82  EP 2 IN
          bmAttributes            3
            Transfer Type            Interrupt
            Synch Type               None
            Usage Type               Data
          wMaxPacketSize     0x0008  1x 8 bytes
          bInterval             255
      Interface Descriptor:
        bLength                 9
        bDescriptorType         4
        bInterfaceNumber        1
        bAlternateSetting       0
        bNumEndpoints           2
        bInterfaceClass        10 CDC Data
        bInterfaceSubClass      0 Unused
        bInterfaceProtocol      0
        iInterface              0
        Endpoint Descriptor:
          bLength                 7
          bDescriptorType         5
          bEndpointAddress     0x03  EP 3 OUT
          bmAttributes            2
            Transfer Type            Bulk
            Synch Type               None
            Usage Type               Data
          wMaxPacketSize     0x0040  1x 64 bytes
          bInterval               0
        Endpoint Descriptor:
          bLength                 7
          bDescriptorType         5
          bEndpointAddress     0x81  EP 1 IN
          bmAttributes            2
            Transfer Type            Bulk
            Synch Type               None
            Usage Type               Data
          wMaxPacketSize     0x0040  1x 64 bytes
          bInterval               0
  Device Status:     0x3100
    (Bus Powered)

Now if you instead compare the information for a PJRC Teensy 3.2 board

  [ 1353.572055] usb 1-3: new full-speed USB device number 9 using xhci_hcd
  [ 1353.701457] usb 1-3: New USB device found, idVendor=16c0, idProduct=0483
  [ 1353.701471] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
  [ 1353.701478] usb 1-3: Product: USB Serial
  [ 1353.701485] usb 1-3: Manufacturer: Teensyduino
  [ 1353.701491] usb 1-3: SerialNumber: 2706960
  [ 1353.703111] cdc_acm 1-3:1.0: ttyACM0: USB ACM device

  kurt@kurt-UP-Turtle:~$ lsusb
  Bus 002 Device 002: ID 8086:0a80 Intel Corp.
  Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
  Bus 001 Device 007: ID 0424:2530 Standard Microsystems Corp.
  Bus 001 Device 006: ID 0424:4603 Standard Microsystems Corp.
  Bus 001 Device 009: ID 16c0:0483 Van Ooijen Technische Informatica Teensyduino Serial
  Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

  kurt@kurt-UP-Turtle:~$ lsusb -v -d 16c0:0483

  Bus 001 Device 009: ID 16c0:0483 Van Ooijen Technische Informatica Teensyduino Serial
  Couldn't open device, some information will be missing
  Device Descriptor:
    bLength                18
    bDescriptorType         1
    bcdUSB               1.01
    bDeviceClass            2 Communications
    bDeviceSubClass         0
    bDeviceProtocol         0
    bMaxPacketSize0        64
    idVendor           0x16c0 Van Ooijen Technische Informatica
    idProduct          0x0483 Teensyduino Serial
    bcdDevice            2.00
    iManufacturer           1
    iProduct                2
    iSerial                 3
    bNumConfigurations      1
    Configuration Descriptor:
      bLength                 9
      bDescriptorType         2
      wTotalLength           67
      bNumInterfaces          2
      bConfigurationValue     1
      iConfiguration          0
      bmAttributes         0xc0
        Self Powered
      MaxPower              100mA
      Interface Descriptor:
        bLength                 9
        bDescriptorType         4
        bInterfaceNumber        0
        bAlternateSetting       0
        bNumEndpoints           1
        bInterfaceClass         2 Communications
        bInterfaceSubClass      2 Abstract (modem)
        bInterfaceProtocol      1 AT-commands (v.25ter)
        iInterface              0
        CDC Header:
          bcdCDC               1.10
        CDC Call Management:
          bmCapabilities       0x01
            call management
          bDataInterface          1
        CDC ACM:
          bmCapabilities       0x06
            sends break
            line coding and serial state
        CDC Union:
          bMasterInterface        0
          bSlaveInterface         1
        Endpoint Descriptor:
          bLength                 7
          bDescriptorType         5
          bEndpointAddress     0x82  EP 2 IN
          bmAttributes            3
            Transfer Type            Interrupt
            Synch Type               None
            Usage Type               Data
          wMaxPacketSize     0x0010  1x 16 bytes
          bInterval              64
      Interface Descriptor:
        bLength                 9
        bDescriptorType         4
        bInterfaceNumber        1
        bAlternateSetting       0
        bNumEndpoints           2
        bInterfaceClass        10 CDC Data
        bInterfaceSubClass      0 Unused
        bInterfaceProtocol      0
        iInterface              0
        Endpoint Descriptor:
          bLength                 7
          bDescriptorType         5
          bEndpointAddress     0x03  EP 3 OUT
          bmAttributes            2
            Transfer Type            Bulk
            Synch Type               None
            Usage Type               Data
          wMaxPacketSize     0x0040  1x 64 bytes
          bInterval               0
        Endpoint Descriptor:
          bLength                 7
          bDescriptorType         5
          bEndpointAddress     0x84  EP 4 IN
          bmAttributes            2
            Transfer Type            Bulk
            Synch Type               None
            Usage Type               Data
          wMaxPacketSize     0x0040  1x 64 bytes
          bInterval               0

You can see some of the differences, in particular, the difference in:

    iManufacturer           1 (error)
    iProduct                2 (error)
    iSerial                 0

    versus

    iManufacturer           1
    iProduct                2
    iSerial                 3

There are many times when this information may not be important to most people, but could be if they for example wish to use multiple of these devices and be able control different sets of servos.

My guess is that some of this could be updated in the file: ...\OpenCM9.04\arduino\opencm_arduino\opencm9.04\variants\OpenCM904\hw\usb_cdc

Again not sure if the boards have a unique serial number or not.

Hope this makes sense.

@chcbaram
Copy link
Contributor

You are right that some information of usb could be updated so we are considering the wrong information to fix it.
There is no serial number for usb. I think it can't be fixed because the bootloader also should be modified for downloading well. As you know, it's not easy to change the bootloader for compatibility.
Thank you for your suggestion.

@KurtE
Copy link
Contributor Author

KurtE commented Mar 28, 2018

Thanks, not sure how doable the Serial number stuff is?

My Quick look at the code, looks like there may be some unique numbers stored in hardware?

D:\GitHub\OpenCM9.04\arduino\opencm_arduino\opencm9.04_release\variants\OpenCM904\hw\usb_cdc\usbd_desc.h:
   55  /* Exported types ------------------------------------------------------------*/
   56  /* Exported constants --------------------------------------------------------*/
   57: #define         DEVICE_ID1          (0x1FFFF7E8)
   58  #define         DEVICE_ID2          (0x1FFFF7EC)
   59  #define         DEVICE_ID3          (0x1FFFF7F0)

Which the function: Get_SerialNum uses:
D:\GitHub\OpenCM9.04\arduino\opencm_arduino\opencm9.04\variants\OpenCM904\hw\usb_cdc\usbd_desc.c:

static void Get_SerialNum(void)
{
  uint32_t deviceserial0, deviceserial1, deviceserial2;
  
  deviceserial0 = *(uint32_t*)DEVICE_ID1;
  deviceserial1 = *(uint32_t*)DEVICE_ID2;
  deviceserial2 = *(uint32_t*)DEVICE_ID3;
  
  deviceserial0 += deviceserial2;
  
  if (deviceserial0 != 0)
  {
    IntToUnicode (deviceserial0, &USBD_StringSerial[2] ,8);
    IntToUnicode (deviceserial1, &USBD_StringSerial[18] ,4);
  }
}

Which could be optionally called in the function:

uint8_t *USBD_VCP_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
  *length = USB_SIZ_STRING_SERIAL;
  
  /* Update the serial number string descriptor with the data from the unique ID*/
  //Get_SerialNum();
  
  return USBD_StringSerial;
}

Which I think should be callable (I think). I believe it is similar to what the Teensy does.... There is then also code on Teensy that then converts to string, and optionally returns that if an app asks for the String Resource of the ID, which is stored in the device descriptor.

@chcbaram
Copy link
Contributor

chcbaram commented Mar 29, 2018

The reason why Get_SerialNum() was commented is to fix the problem on the macOS.
When I tesed it on macOS, the serial port number appeared differently everytime when the board was connected to mac. I guess it could depend on macOS version.
After testing again on macOS, it will be uncommented on next release.

P.S.
I found that the serial port number appeared differently when "iSerial 0" is changed to iSerial 3" like below.
before

const uint8_t hUSBDDeviceDesc[USB_LEN_DEV_DESC]= {
  ...
  USBD_IDX_MFC_STR,           /* Index of manufacturer string */
  USBD_IDX_PRODUCT_STR,       /* Index of product string */
  0,//USBD_IDX_SERIAL_STR,        /* Index of serial number string */
  USBD_MAX_NUM_CONFIGURATION  /* bNumConfigurations */
}; /* USB_DeviceDescriptor */

after

const uint8_t hUSBDDeviceDesc[USB_LEN_DEV_DESC]= {
  ...
  USBD_IDX_MFC_STR,           /* Index of manufacturer string */
  USBD_IDX_PRODUCT_STR,       /* Index of product string */
  USBD_IDX_SERIAL_STR,        /* Index of serial number string */
  USBD_MAX_NUM_CONFIGURATION  /* bNumConfigurations */
}; /* USB_DeviceDescriptor */

I think, it's because of different code between bootloader and arduino firmware.
As I said, it's not possible to modify the bootloader.
I have to check what happen when Get_SerialNum() is uncommented while USBD_IDX_SERIAL_STR is not changed.

Thank you for the comment.

@KurtE
Copy link
Contributor Author

KurtE commented Mar 29, 2018

Again not sure how much of a help I am here, very little experience with these processors. More experience with Teensy boards by PJRC including doing some work to help support host USB on the T3.6.
Also have not found good reference manual for these processors, that show registers and the like.

My guess is the Bootloader vs User code, should not mater? I would think the USB negotiation is done early on... Although maybe differences especially if for example the PID/VID is different when in a programming mode...

Somethings I notice different between Teensy serial number stuff (https://github.com/PaulStoffregen/cores/blob/master/teensy3/usb_desc.c#L1444) and here

a) He is using just extracting a 32 bit number as the serial number... You are using larger number of characters. That is he is outputting up to 10 digits and only enough characters for the actual number.

b) There is a check/fix for MAC bug

	if (num < 10000000) num = num * 10;
	ultoa(num, buf, 10);
	for (i=0; i<10; i++) {
		char c = buf[i];
		if (!c) break;
		usb_string_serial_number_default.wString[i] = c;
	}
	usb_string_serial_number_default.bLength = i * 2 + 2;

c) I don't fully understand how your descriptor stuff works. On the Teensy there is a top level descriptor list, which is used to build the data. This includes the string descriptors for VID/PID/Serial... (About line 1485 in file I showed).

With your code, I think this is ctonrolled in the _Device_cb structure.

typedef struct _Device_cb
{
  uint8_t  (*Init)             (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);
  uint8_t  (*DeInit)           (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx);
 /* Control Endpoints*/
  uint8_t  (*Setup)            (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef  *req);  
  uint8_t  (*EP0_TxSent)       (struct _USBD_HandleTypeDef *pdev );    
  uint8_t  (*EP0_RxReady)      (struct _USBD_HandleTypeDef *pdev );  
  /* Class Specific Endpoints*/
  uint8_t  (*DataIn)           (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);   
  uint8_t  (*DataOut)          (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); 
  uint8_t  (*SOF)              (struct _USBD_HandleTypeDef *pdev); 
  uint8_t  (*IsoINIncomplete)  (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); 
  uint8_t  (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum);   

  uint8_t  *(*GetHSConfigDescriptor)(uint16_t *length); 
  uint8_t  *(*GetFSConfigDescriptor)(uint16_t *length);   
  uint8_t  *(*GetOtherSpeedConfigDescriptor)(uint16_t *length);
  uint8_t  *(*GetDeviceQualifierDescriptor)(uint16_t *length);
#if (USBD_SUPPORT_USER_STRING == 1)
  uint8_t  *(*GetUsrStrDescriptor)(struct _USBD_HandleTypeDef *pdev ,uint8_t index,  uint16_t *length);   
#endif  

Note the last item is for String descriptors, and is under #9

Which looks like it is not set

#define USBD_SUPPORT_USER_STRING              0

But again I don't fully understand all of this code

@chcbaram
Copy link
Contributor

Thanks @KurtE

The usb codes of OpenCM is based on stm32cubF1 middleware provided by ST.
I also don't understand full function of usb in this library so I kept trying not to change the reference code. But the bootloader was developed few years ago, so there were different library used in bootloader.

When downloading in Arduino IDE, the OpenCM goes to reset and the usb is disconnected and the usb is reconnected by the bootloader. At this time, the different serial port number could appear if bootloader and firmware have different code.

I'll check what you said. I think it could take some time.
If you have any idea, please let me know.

Thanks again.

@KurtE
Copy link
Contributor Author

KurtE commented Mar 30, 2018

Yes - looks like it might be difficult. I did hack up my system to allow me to run the code from the development branch and did as you mention of change the iSerial from 0->3 and yes the board is now getting two different comm port numbers on windows.

I verified looking on unix and with this configuration, it gets shows that iSerial is still 0 if I plug the board in holding the user button... Also shows different product and vendor names as well and a few other differences in the linux verbose output.

What what it is worth, what they did with the Teensy is when you reboot into program mode, it gives it a different device ID, it also does not configure as CDC ACM mode but instead a RAW HID mode (so no serial port assigned...) But that does not help you here.

Good luck, hopefully there is some way to make it work and I may play around some more, but unfortunately don't have any new ideas yet.

Also I am not sure if the bootloader sources are in here? And how hard it is to update? Can I use ST-LINK to update?

Kurt

@KurtE
Copy link
Contributor Author

KurtE commented Apr 1, 2018

A few more thoughts. Again wondering about is the sources for the bootloader available?

If so, maybe we could update the bootloader to also return the Serial number?

If so, maybe could setup a sketch or like to update the firmware on existing 904 boards. I believe this is possible as, it looks like someone already built a sketch to update the bootloader to one that is compatible with maple: https://github.com/Gregwar/maple-bootloader-robotis/blob/master/sketch/opencm904_maple_loader/opencm904_maple_loader.ino

@KurtE
Copy link
Contributor Author

KurtE commented Apr 3, 2018

@chcbaram

I don't know if you have been following the issue #20 (#20)

But turned out my old 904B had a real old bootloader on it which was only compatible with the Open_CM ide...

I found this out by writing a sketch that dumped the bootloaders of a newer board and my old board and verified that they were very different. Files up on other issue.

I found a sketch that someone had written to update the bootloader to be compatible with Maple development...

So today I hacked up that sketch to instead use the data I dumped from the newer 904A board and built and downloaded it using the Open_CM IDE and now the old board works with Arduino IDE as well as with R+Manager... Other thread has zip file with this program

So If we can build a new firmware that has the iSerial number and same method of generating the serial number from the 96 bit unique ID, it should not be hard for users to upgrade their boards to this functionality.

@chcbaram
Copy link
Contributor

chcbaram commented Apr 5, 2018

@KurtE

Thanks for the information.
I also know that there is a way to upgrade from the sketch but as you know, it's not possible to recover the board when the something happen during updating.
If the bootloader doesn't work, you need the tools for recovering bootloader so I can't give a way officially to upgrade the bootloader like that without any safe solution.
I think you understand me.

Thanks again for trying to improve.

@KurtE
Copy link
Contributor Author

KurtE commented Apr 5, 2018

@chcbaram

Thanks for looking into this. I am guessing that this is going to be a no fix...

I can totally understand, not wanting to risk it. But do think there could maybe be a two pronged approach. That is ship all new ones with the updated bootloader and offer ways for people to upgrade older ones. I am assuming that the R+ Manager only reports the current bootloader version and does not have the ability to update it.

Note: the Maple program I mentioned in the other issue, also had secondary way to update the firmware, which looks like a pain. That is, I believe the underlying STM32 has the ability to download a bootloader using Serial1 (how to get one on there when they are new), and the Readme of the maple project shows steps needed to enter into bootloader download mode.... But again probably requires additional hardware (like a USB to UART converter)...

Obviously we can get by without fixing this. But might be nice, especially if someone wishes to use multiple of these units on their Robot or other processor...

Currently I am assuming that the bootloader is NOT open source?

@chcbaram
Copy link
Contributor

chcbaram commented Apr 5, 2018

@KurtE

I understand what you said. I am also engineer who want to give a lot of options to the user.
As I know, the bootloader source was removed before but I don't know the reason exactly.
I guess it's the policy of the company.
If you want to see the source code, it's the link I modified unofficially before.
https://github.com/chcbaram/OpenCM9.04_ArduBoot

As I said, it's not official version. It's my personal modified version so it could be different from official version.
you just look it how the bootloader is working.

Thanks again.

@KurtE
Copy link
Contributor Author

KurtE commented Apr 6, 2018

Thanks, will take a look. Not sure what toolchain was used to build... Probably can setup something that uses tools that are part of the Arduino install.

@chcbaram
Copy link
Contributor

chcbaram commented Apr 7, 2018

@KurtE

I just modifed Makefile to build for gcc5. The build was successfull but I didn't test it's working.
So you can build by gcc5 below link.
https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q2-update

@robotpilot
Copy link
Member

This issue will be closed since there were no actions for a while. You can reopen this issue to show this issue to the users whenever. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants