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

firmware: select string descriptors at run time #82

Merged
merged 2 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}