erikkaashoek / tinySA

tiny Spectrum Analyzer
219 stars 48 forks source link

Identical device serial numbers #85

Open FinnHoller opened 9 months ago

FinnHoller commented 9 months ago

I would like to connect multiple tinySA devices to the same computer, identifying them based on their serial number as reported by udev.

It turns out that multiple of my tinySA seem to share the same serial number (400). Is there a way to change this?

Ho-Ro commented 9 months ago

You can build your own FW with hardcoded serial numbers for each of your devices, see the source code.

Lathe26 commented 9 months ago

I would suggest using the STM32's 96-bit unique ID, either directly or better yet hashed, to create a unique serial number per device. The STM32F303xC Reference Manual RM0316 documents the unique ID in section 34.1.

The benefit for the user would be that if a user connects more than one TinySA Ultra to a computer, then the COM port or /dev/tty will stay assigned to the same TinySA Ultra. Probably not a top priority issue, but it would be a good-to-have feature.

Side note: if there is a need to communicate the firmware version number, that could still be done by prefixing the serial number string with the current version number format. Alternatively, the firmware version number can be communicated using the bcdDevice field of the USB Device Descriptor. It uses BCD format typically as 0xMMJJ or 0xMMJK where M = major number, J = minor number, K = patch number (your choice of each format).

Ho-Ro commented 3 months ago

Proof of concept for the unique ID

Change static const uint8_t vcom_string3[] = { ... in usbcfg.c:

uint8_t vcom_string3[50] = {            // 2 byte config + 24 wchar string
  USB_DESC_BYTE(50),                    // bLength.
  USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType.
};

static const uint8_t HEX[] = {
  '0', '1', '2', '3', '4', '5', '6', '7',
  '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};

void get_uuid() {
  uint8_t *uuid = (uint8_t *)0x1FFFF7AC;      // Unique device ID register (12 byte)
  for ( int iii = 2; iii < 50; iii+=4 ) {     // put into serial number string at these positions
    uint8_t idPart = *uuid++;                 // fetch next byte
    vcom_string3[iii] = HEX[idPart >> 4];     // encode high nibble as hex char, next byte is 0x00
    vcom_string3[iii+2] = HEX[idPart & 0x0F]; // encode low nibble as hex char, next byte is 0x00
  }
}

declare it extern in usbcfg.h: extern void get_uuid(void); Call get_uuid() early in main().

I did this for tinySA as well as for NanoVNA

[Jun27 02:56] usb 6-2: USB disconnect, device number 57
[  +1,507927] usb 6-2: new full-speed USB device number 58 using uhci_hcd
[  +0,185877] usb 6-2: New USB device found, idVendor=0483, idProduct=5740, bcdDevice= 2.00
[  +0,000020] usb 6-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  +0,000007] usb 6-2: Product: NanoVNA-H
[  +0,000006] usb 6-2: Manufacturer: nanovna.com
[  +0,000005] usb 6-2: SerialNumber: 41001B001457345435333120
[  +0,004038] cdc_acm 6-2:1.0: ttyACM0: USB ACM device

The 12 bytes of the UUID correspond to this structure, STM32 uses little endian:

struct UUID {
    uint16_t X;  // X coordinate of chip on wafer
    uint16_t Y;  // Y coordinate of chip on wafer
    uint8_t WAF;  // Wafer number as byte
    char LOT[7];  // Lot number as string w/o zero term
};

Im my code above the USB sernum string is shown as uint8_t SERNUM[12] formatted as %02X w/o interpreting any value.

I found also this STM example code how to represent the USB sernum string.

Lathe26 commented 2 months ago

At a glance, the code looks fine. I have not confirmed/tested it. (just adding a comment as the original issue opener)