fl16: Make dynamic serial number a little more generic

First step towards upstreaming.

Signed-off-by: Daniel Schaefer <dhs@frame.work>
This commit is contained in:
Daniel Schaefer 2023-03-23 13:09:09 +08:00
parent ef518f5b4b
commit 4827822cdc
8 changed files with 85 additions and 71 deletions

View File

@ -0,0 +1,51 @@
// Copyright 2022 Framework Computer
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quantum.h"
#include "dyn_serial.h"
#include "usb_descriptor.h"
#include "usb_descriptor_common.h"
// Prefix string literal with L for descriptors
#ifdef SERIAL_NUMBER
USB_Descriptor_String_t PROGMEM SerialNumberString = {
.Header = {
.Size = sizeof(FALLBACK_SERIAL_NUMBER),
.Type = DTYPE_String
},
.UnicodeString = FALLBACK_SERIAL_NUMBER
};
char ascii_serialnum[SERIALNUM_LEN+1];
void *dyn_serial_number_string(void) {
// Exit early, if it was previously read and converted
if (ascii_serialnum[0] != '\0' || ascii_serialnum[0] == 0xFF) {
return &SerialNumberString;
}
// Read ASCII serial number from memory-mapped flash
char *serialnum_ptr = (char*) (FLASH_OFFSET + LAST_4K_BLOCK);
memcpy(ascii_serialnum, serialnum_ptr, SERIALNUM_LEN);
// Just keep fallback serialnumber if the flash is erased
if (ascii_serialnum[0] == 0xFF) {
return &SerialNumberString;
}
// Convert to UCS-2, which is equivalent to UTF-16, if the input is ASCII
for (int i = 0; i < SERIALNUM_LEN; i++) {
if (ascii_serialnum[i] > 128) {
dprintf("Serial number character %d is not valid ASCII.", ascii_serialnum[i]);
SerialNumberString.Header.Size = i * 2;
break;
}
SerialNumberString.UnicodeString[i] = ascii_serialnum[i];
}
return &SerialNumberString;
}
uint16_t dyn_serial_number_string_len(void) {
return pgm_read_byte(&SerialNumberString.Header.Size);
}
#endif

View File

@ -0,0 +1,21 @@
// Copyright 2022 Framework Computer
// SPDX-License-Identifier: GPL-2.0-or-later
//#include "quantum.h"
void *dyn_serial_number_string(void);
uint16_t dyn_serial_number_string_len(void);
// The serial number is written to the last 4K block in the first 1M of flash
#define FLASH_OFFSET 0x10000000
#define LAST_4K_BLOCK 0xff000
#define SERIALNUM_LEN 18
// 18-digit serial number. Must be programmed at factory
// TODO: Figure out how to do that. Probably a script to compile qmk
// Must be wide-string (UTF-16)
// KDK = Keyboard RGB Backlight
// KDW = Keyboard White Backlight
// KDN = Keyboard RGB Gridpad
// KDM = Keyboard White Numpad
#define FALLBACK_SERIAL_NUMBER L"FRAKDKEN0100000000"
_Static_assert(sizeof(FALLBACK_SERIAL_NUMBER) == (SERIALNUM_LEN+1)*2, "Fallback serial number must be same length");

View File

@ -8,6 +8,9 @@
#if defined(RGB_MATRIX_ENABLE)
#include "rgb_matrix.h"
#endif
#ifdef SERIAL_NUMBER
#include "dyn_serial.h"
#endif
enum factory_commands {
f_emu_keypress = 0x01, // Next byte is keycode

View File

@ -4,53 +4,6 @@
#include "quantum.h"
#include "lotus.h"
#include "usb_descriptor.h"
#include "usb_descriptor_common.h"
// Prefix string literal with L for descriptors
#ifdef SERIAL_NUMBER
USB_Descriptor_String_t PROGMEM SerialNumberString = {
.Header = {
.Size = sizeof(FALLBACK_SERIAL_NUMBER),
.Type = DTYPE_String
},
.UnicodeString = FALLBACK_SERIAL_NUMBER
};
char ascii_serialnum[SERIALNUM_LEN+1];
void *lotus_serial_number_string(void) {
// Exit early, if it was previously read and converted
if (ascii_serialnum[0] != '\0' || ascii_serialnum[0] == 0xFF) {
return &SerialNumberString;
}
// Read ASCII serial number from memory-mapped flash
char *serialnum_ptr = (char*) (FLASH_OFFSET + LAST_4K_BLOCK);
memcpy(ascii_serialnum, serialnum_ptr, SERIALNUM_LEN);
// Just keep fallback serialnumber if the flash is erased
if (ascii_serialnum[0] == 0xFF) {
return &SerialNumberString;
}
// Convert to UCS-2, which is equivalent to UTF-16, if the input is ASCII
for (int i = 0; i < SERIALNUM_LEN; i++) {
if (ascii_serialnum[i] > 128) {
dprintf("Serial number character %d is not valid ASCII.", ascii_serialnum[i]);
SerialNumberString.Header.Size = i * 2;
break;
}
SerialNumberString.UnicodeString[i] = ascii_serialnum[i];
}
return &SerialNumberString;
}
uint16_t lotus_serial_number_string_len(void) {
return pgm_read_byte(&SerialNumberString.Header.Size);
}
#endif
void keyboard_post_init_kb(void) {
keyboard_post_init_user();

View File

@ -32,20 +32,3 @@ enum lotus_keycodes {
#else
#define IS31FL3743A_ENABLE_GPIO GP29
#endif
void *lotus_serial_number_string(void);
uint16_t lotus_serial_number_string_len(void);
// The serial number is written to the last 4K block in the first 1M of flash
#define FLASH_OFFSET 0x10000000
#define LAST_4K_BLOCK 0xff000
#define SERIALNUM_LEN 18
// 18-digit serial number. Must be programmed at factory
// TODO: Figure out how to do that. Probably a script to compile qmk
// Must be wide-string (UTF-16)
// KDK = Keyboard RGB Backlight
// KDW = Keyboard White Backlight
// KDN = Keyboard RGB Gridpad
// KDM = Keyboard White Numpad
#define FALLBACK_SERIAL_NUMBER L"FRAKDKEN0100000000"
_Static_assert(sizeof(FALLBACK_SERIAL_NUMBER) == (SERIALNUM_LEN+1)*2, "Fallback serial number must be same length");

View File

@ -16,6 +16,6 @@ BACKLIGHT_DRIVER = pwm
CUSTOM_MATRIX = lite
SRC += matrix.c analog.c
SRC += factory.c
SRC += dyn_serial.c factory.c
DEFAULT_FOLDER = lotus/ansi

View File

@ -41,7 +41,7 @@
#include "usb_descriptor.h"
#include "usb_descriptor_common.h"
#include "lotus.h"
#include "dyn_serial.h"
#ifdef JOYSTICK_ENABLE
# include "joystick.h"
@ -1139,8 +1139,9 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
#if defined(SERIAL_NUMBER)
case 0x03:
// TODO: Give these functions a generic name and let anyone override it
Address = lotus_serial_number_string();
Size = lotus_serial_number_string_len();
// Framework 16 uses this
Address = dyn_serial_number_string();
Size = dyn_serial_number_string_len();
break;
#endif

View File

@ -30,6 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "debug.h"
#include "wait.h"
#include "usb_descriptor_common.h"
#include "dyn_serial.h"
#ifdef RAW_ENABLE
# include "raw_hid.h"
@ -761,7 +762,7 @@ const PROGMEM usbStringDescriptor_t usbStringDescriptorProduct = {
.bString = USBSTR(PRODUCT)
};
// THIS IS NOT USED by Lotus. TODO: Implement flexible serial number here
// THIS IS NOT USED by Framework 16. TODO: Implement dynamic serial number here
#if defined(SERIAL_NUMBER)
const PROGMEM usbStringDescriptor_t usbStringDescriptorSerial =
.header = {
@ -1035,8 +1036,9 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
break;
#if defined(SERIAL_NUMBER)
case 3: // iSerialNumber
usbMsgPtr = (usbMsgPtr_t)lotus_serial_number_string();
len = lotus_serial_number_string_len();
// Not using this on Framework 16
usbMsgPtr = (usbMsgPtr_t)dynamic_serial_number_string();
len = dynamic_serial_number_string_len();
break;
#endif
}