Skip to content

Commit

Permalink
Merge pull request #82 from mossmann/string-descriptors
Browse files Browse the repository at this point in the history
firmware: select string descriptors at run time
  • Loading branch information
mossmann authored Jun 24, 2024
2 parents 174dc21 + 3e6a75b commit 2523d9a
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 70 deletions.
16 changes: 16 additions & 0 deletions firmware/src/board_rev.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,19 @@ __attribute__((weak)) uint16_t get_board_revision(void)
{
return (_BOARD_REVISION_MAJOR_ << 8) | _BOARD_REVISION_MINOR_;
}

/**
* Return the manufacturer string.
*/
__attribute__((weak)) const char *get_manufacturer_string(void)
{
return "Apollo Project";
}

/**
* Return the product string.
*/
__attribute__((weak)) const char *get_product_string(void)
{
return "Apollo Debugger";
}
9 changes: 9 additions & 0 deletions firmware/src/board_rev.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,14 @@ void detect_hardware_revision(void);
*/
uint16_t get_board_revision(void);

/**
* Return the manufacturer string.
*/
const char *get_manufacturer_string(void);

/**
* Return the product string.
*/
const char *get_product_string(void);

#endif
16 changes: 16 additions & 0 deletions firmware/src/boards/cynthion_d11/board_rev.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,20 @@ uint16_t get_board_revision(void)
return revision;
}

/**
* Return the manufacturer string.
*/
const char *get_manufacturer_string(void)
{
return (gsg_production) ? "Great Scott Gadgets" : "Apollo Project";
}

/**
* Return the product string.
*/
const char *get_product_string(void)
{
return (gsg_production) ? "Cynthion Apollo Debugger" : "Apollo Debugger";
}

#endif
143 changes: 73 additions & 70 deletions firmware/src/mcu/samd11/usb_descriptors.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019-2024 Great Scott Gadgets <[email protected]>
* Copyright (c) 2019 Katherine J. Temkin <[email protected]>
* Copyright (c) 2019 Great Scott Gadgets <[email protected]>
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
Expand All @@ -27,8 +27,16 @@

#include "tusb.h"
#include "board_rev.h"
#include "usb/usb_protocol.h"

#define SERIAL_NUMBER_STRING_INDEX 3
enum
{
STRING_INDEX_LANGUAGE = 0,
STRING_INDEX_MANUFACTURER = 1,
STRING_INDEX_PRODUCT = 2,
STRING_INDEX_SERIAL_NUMBER = 3,
STRING_INDEX_MICROSOFT = 0xee,
};

//--------------------------------------------------------------------+
// Device Descriptors
Expand All @@ -52,15 +60,17 @@ tusb_desc_device_t desc_device =
.idVendor = 0x1d50,
.idProduct = 0x615c,

.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = SERIAL_NUMBER_STRING_INDEX,
.iManufacturer = STRING_INDEX_MANUFACTURER,
.iProduct = STRING_INDEX_PRODUCT,
.iSerialNumber = STRING_INDEX_SERIAL_NUMBER,

.bNumConfigurations = 0x01
};

// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
/**
* Return pointer to device descriptor.
* Invoked by GET DEVICE DESCRIPTOR request.
*/
uint8_t const * tud_descriptor_device_cb(void)
{
desc_device.bcdDevice = get_board_revision();
Expand Down Expand Up @@ -95,9 +105,10 @@ uint8_t const desc_configuration[] =
};


// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
/**
* Return pointer to configuration descriptor.
* Invoked by GET CONFIGURATION DESCRIPTOR request.
*/
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
Expand All @@ -108,32 +119,27 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+

#define STRING_DESC_LEN(x) (2 + ((x) * 2))
#define STRING_DESC_MAX_CHARS 31
#define SERIAL_NUMBER_CHARS 26

// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"Great Scott Gadgets", // 1: Manufacturer
"Apollo Debugger", // 2: Product
NULL, // 3: Serials, should use chip ID
};
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bString[STRING_DESC_MAX_CHARS];
} desc_string_t __attribute__((aligned(2)));

static uint16_t _desc_str[34];
static desc_string_t desc_string;

static char serial_string[SERIAL_NUMBER_CHARS + 1];

/**
* Returns a USB string descriptor that describes this device's unique ID.
* Return the microcontroller's unique ID in Base32.
*/
static uint16_t *get_serial_number_string_descriptor(void)
static inline char *get_serial_number_string(void)
{
const unsigned serial_number_chars = 26;

int count = 0;

//
// Read and save the device serial number as normal Base32.
//

// Documented in section 9.3.3 of D21 datasheet, page 32 (rev G), but no header file,
// these are not contiguous addresses.
uint32_t ser[5];
Expand All @@ -145,72 +151,69 @@ static uint16_t *get_serial_number_string_descriptor(void)

uint8_t *tmp = (uint8_t *)ser;

// Populate the length and string type, as these are the first two bytes
// of our descriptor...
_desc_str[count++] = (TUSB_DESC_STRING << 8 ) | ((serial_number_chars * 2) + 2);

// ... and convert our serial number into Base32.
int buffer = tmp[0];
int next = 1;
int bits_left = 8;

for (unsigned i = 0; i < serial_number_chars; ++i) {
for (unsigned i = 0; i < SERIAL_NUMBER_CHARS; ++i) {
if (bits_left < 5) {
buffer <<= 8;
buffer |= tmp[next++] & 0xff;
bits_left += 8;
}
bits_left -= 5;
int index = (buffer >> bits_left) & 0x1f;
_desc_str[count++] = index + (index < 26 ? 'A' : '2' - 26); // RFC 4648 Base32
serial_string[count++] = index + (index < 26 ? 'A' : '2' - 26); // RFC 4648 Base32
}
serial_string[count] = 0;

return _desc_str;
return serial_string;
}

// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
/**
* Return pointer to string descriptor.
* Invoked by GET STRING DESCRIPTOR request.
*/
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
uint8_t chr_count;

// If we're looking for the "supported languages" descriptor, return it directly.
if (index == 0) {
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}
// If this is a request for the serial number, return the device's unique ID>
else if (index == SERIAL_NUMBER_STRING_INDEX) {
return get_serial_number_string_descriptor();
const char* str;

desc_string.bDescriptorType = TUSB_DESC_STRING;

switch (index) {
case STRING_INDEX_LANGUAGE:
desc_string.bLength = STRING_DESC_LEN(1);
desc_string.bString[0] = USB_LANGID_EN_US;
return (uint16_t const *) &desc_string;
case STRING_INDEX_MANUFACTURER:
str = get_manufacturer_string();
break;
case STRING_INDEX_PRODUCT:
str = get_product_string();
break;
case STRING_INDEX_SERIAL_NUMBER:
str = get_serial_number_string();
break;
case STRING_INDEX_MICROSOFT:
// Microsoft OS 1.0 String Descriptor
str = "MSFT100\xee";
break;
default:
return NULL;
}

// Otherwise, take the ASCII string provided and encode it as UTF-16.
else {
// Cap at max chars.
chr_count = strlen(str);
if (chr_count > STRING_DESC_MAX_CHARS) chr_count = STRING_DESC_MAX_CHARS;

const char* str;
if (index == 0xee) {
// Microsoft OS 1.0 String Descriptor
str = "MSFT100\xee";
} else {
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) {
return NULL;
}

str = string_desc_arr[index];
}

// Cap at max char
chr_count = strlen(str);
if ( chr_count > 31 ) chr_count = 31;

for(uint8_t i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
// Encode string as UTF-16.
for (uint8_t i=0; i<chr_count; i++) {
desc_string.bString[i] = str[i];
}

// first byte is length (including header), second byte is string type
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
desc_string.bLength = STRING_DESC_LEN(chr_count);

return _desc_str;
return (uint16_t const *) &desc_string;
}

0 comments on commit 2523d9a

Please sign in to comment.