From 769bf30f87c36420dd325062e2e48e0d3dc8d5f4 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 7 Aug 2023 13:36:05 +0800 Subject: [PATCH 1/3] Add scripts to build serialnumber UF2 file Signed-off-by: Daniel Schaefer --- scripts/serial.py | 29 +++++++++++++++++++++++++++++ scripts/serial.sh | 3 +++ 2 files changed, 32 insertions(+) create mode 100755 scripts/serial.py create mode 100755 scripts/serial.sh diff --git a/scripts/serial.py b/scripts/serial.py new file mode 100755 index 0000000..f70b37e --- /dev/null +++ b/scripts/serial.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +import zlib + +ledmatrix_1 = b'FRAKDEAM1100000000' # POC 1 +ledmatrix_2 = b'FRAKDEBZ4100000000' # EVT 1, config 1 +ledmatrix_3 = b'FRAKDEBZ4200000000' # EVT 1, config 2 (27k resistor) + +# This section is for modifying +selected = ledmatrix_2 +year = b'3' # 2023 +week = b'01' +day = b'1' +part_sn = b'0001' + +config = selected[8:10] +serial_rev = b'\x01' +snum = selected +print(serial_rev + snum) +snum = snum[0:8] + config + year + week + day + part_sn + +checksum = zlib.crc32(serial_rev + snum) +print(serial_rev + snum) + +print('Checksum:', hex(zlib.crc32(snum))) +print('Digest: ', hex(checksum)) +with open('serial.bin', 'wb') as f: + f.write(serial_rev) + f.write(snum) + f.write(checksum.to_bytes(4, 'little')) diff --git a/scripts/serial.sh b/scripts/serial.sh new file mode 100755 index 0000000..fb5c10a --- /dev/null +++ b/scripts/serial.sh @@ -0,0 +1,3 @@ +#!/bin/sh +./serial.py +../qmk_firmware/util/uf2conv.py serial.bin -o serial.uf2 -b 0x100ff000 -f rp2040 --convert From a1713eb49728072e938792ce607cb7843bf979f9 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 7 Aug 2023 13:33:52 +0800 Subject: [PATCH 2/3] Use CRC32B to verify serial number The previously used check for 0x00 or 0xFF was too primitive and resulted in lots of false positives if other firmware was flashed. Signed-off-by: Daniel Schaefer --- Cargo.lock | 16 ++++++++++++ b1display/src/main.rs | 2 +- c1minimal/src/main.rs | 2 +- fl16-inputmodules/Cargo.toml | 9 ++++--- fl16-inputmodules/src/serialnum.rs | 41 +++++++++++++++++++++++++----- flash_layout.md | 38 +++++++++++++++++++++++++++ ledmatrix/src/main.rs | 2 +- scripts/serial.py | 12 ++++++--- 8 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 flash_layout.md diff --git a/Cargo.lock b/Cargo.lock index 607dff7..dc6c54b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -561,6 +561,15 @@ dependencies = [ "windows 0.46.0", ] +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + [[package]] name = "crc-any" version = "2.4.3" @@ -570,6 +579,12 @@ dependencies = [ "debug-helper", ] +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + [[package]] name = "crc32fast" version = "1.3.2" @@ -763,6 +778,7 @@ version = "0.1.5" dependencies = [ "cortex-m", "cortex-m-rt", + "crc", "defmt", "defmt-rtt", "embedded-graphics", diff --git a/b1display/src/main.rs b/b1display/src/main.rs index ff5bbf8..81ac88a 100644 --- a/b1display/src/main.rs +++ b/b1display/src/main.rs @@ -114,7 +114,7 @@ fn main() -> ! { let mut serial = SerialPort::new(&usb_bus); let serialnum = if let Some(serialnum) = get_serialnum() { - serialnum + serialnum.serialnum } else { DEFAULT_SERIAL }; diff --git a/c1minimal/src/main.rs b/c1minimal/src/main.rs index 0da4d8f..9967774 100644 --- a/c1minimal/src/main.rs +++ b/c1minimal/src/main.rs @@ -103,7 +103,7 @@ fn main() -> ! { let mut serial = SerialPort::new(&usb_bus); let serialnum = if let Some(serialnum) = get_serialnum() { - serialnum + serialnum.serialnum } else { DEFAULT_SERIAL }; diff --git a/fl16-inputmodules/Cargo.toml b/fl16-inputmodules/Cargo.toml index 2825032..d8105fa 100644 --- a/fl16-inputmodules/Cargo.toml +++ b/fl16-inputmodules/Cargo.toml @@ -4,6 +4,7 @@ name = "fl16-inputmodules" version = "0.1.5" [dependencies] +crc = "3.0" cortex-m = "0.7" cortex-m-rt = "0.7.3" embedded-hal = { version = "0.2.7", features = ["unproven"] } @@ -15,7 +16,7 @@ defmt-rtt = "0.4" rp2040-panic-usb-boot = "0.5.0" # Not using an external BSP, we've got the Framework Laptop 16 BSPs locally in this crate -rp2040-hal = { version="0.8", features=["rt", "critical-section-impl"] } +rp2040-hal = { version = "0.8", features = ["rt", "critical-section-impl"] } rp2040-boot2 = "0.3" # USB Serial @@ -43,6 +44,6 @@ ws2812-pio = { version = "0.6.0", optional = true } [features] default = [] -ledmatrix = [ "is31fl3741" ] -b1display = [ "st7306", "embedded-graphics", "tinybmp" ] -c1minimal = ["smart-leds", "ws2812-pio" ] +ledmatrix = ["is31fl3741"] +b1display = ["st7306", "embedded-graphics", "tinybmp"] +c1minimal = ["smart-leds", "ws2812-pio"] diff --git a/fl16-inputmodules/src/serialnum.rs b/fl16-inputmodules/src/serialnum.rs index 7d7850b..545054a 100644 --- a/fl16-inputmodules/src/serialnum.rs +++ b/fl16-inputmodules/src/serialnum.rs @@ -3,16 +3,43 @@ const FLASH_OFFSET: usize = 0x10000000; const LAST_4K_BLOCK: usize = 0xff000; const SERIALNUM_LEN: usize = 18; -pub fn get_serialnum() -> Option<&'static str> { +#[repr(packed)] +pub struct SerialnumStructRaw { + sn_rev: u8, + serialnum: [u8; SERIALNUM_LEN], + crc32: [u8; 4], +} + +pub struct SerialnumStruct { + pub serialnum: &'static str, +} + +pub fn get_serialnum() -> Option { // Flash is mapped into memory, just read it from there let ptr: *const u8 = (FLASH_OFFSET + LAST_4K_BLOCK) as *const u8; - unsafe { - let slice: &[u8] = core::slice::from_raw_parts(ptr, SERIALNUM_LEN); - if slice[0] == 0xFF || slice[0] == 0x00 { - return None; - } - core::str::from_utf8(slice).ok() + let sn_raw_ptr = ptr as *const SerialnumStructRaw; + let sn_raw = unsafe { sn_raw_ptr.as_ref()? }; + + // Only rev 1 supported + if sn_raw.sn_rev != 1 { + return None; } + + let crc: crc::Crc = crc::Crc::::new(&crc::CRC_32_ISO_HDLC); + let mut digest = crc.digest(); + digest.update(&[sn_raw.sn_rev]); + digest.update(&sn_raw.serialnum); + let calc_checksum = digest.finalize(); + + let actual_checksum = u32::from_le_bytes(sn_raw.crc32); + // Checksum invalid, serial fall back to default serial number + if calc_checksum != actual_checksum { + return None; + } + + Some(SerialnumStruct { + serialnum: core::str::from_utf8(&sn_raw.serialnum).ok()?, + }) } /// Get the firmware version in a format for USB Device Release diff --git a/flash_layout.md b/flash_layout.md new file mode 100644 index 0000000..ec4e1c7 --- /dev/null +++ b/flash_layout.md @@ -0,0 +1,38 @@ +# Flash Layout + +The flash is 1MB large and consists of 256 4K blocks. +The last block is used to store the serial number. + +###### LED Matrix + +| Start | End | Size | Name | +|----------|----------|---------------|--------------------| +| 0x000000 | Dynamic | Roughly 40K | Firmware | +| TBD | 0x0FF000 | TBD | Persistent Storage | +| 0x0FF000 | 0x100000 | 0x1000 (4K) | Serial Number | + +###### QMK Keyboards + +| Start | End | Size | Name | +|----------|----------|---------------|--------------------| +| 0x000000 | Dynamic | Roughly 60K | Firmware | +| 0xef000 | 0x0FF000 | 0x10000 (16K) | Persistent Storage | +| 0x0FF000 | 0x100000 | 0x01000 (4K) | Serial Number | + +## Serial Number + +- 1 byte serial number revision (== 1) +- 18 bytes serial number +- 1 byte hardware revision +- 4 byte CRC checksum over serial number (CRC32B, same as Python's `zlib.crc32()`) + +Hardware Revisions: + +- B1 Display + - 1 First Prototype, very early prototype +- LED Matrix + - 1 First Prototype (ATC) + - 2 Second Prototype (BizLink) + - 3 Third Prototype, 27k Resistor +- Keyboard, Numpad, Macropad + - 1 First Prototype diff --git a/ledmatrix/src/main.rs b/ledmatrix/src/main.rs index 6e8f639..048cada 100644 --- a/ledmatrix/src/main.rs +++ b/ledmatrix/src/main.rs @@ -184,7 +184,7 @@ fn main() -> ! { let mut serial = SerialPort::new(&usb_bus); let serialnum = if let Some(serialnum) = get_serialnum() { - serialnum + serialnum.serialnum } else { DEFAULT_SERIAL }; diff --git a/scripts/serial.py b/scripts/serial.py index f70b37e..aca3396 100755 --- a/scripts/serial.py +++ b/scripts/serial.py @@ -1,9 +1,15 @@ #!/usr/bin/env python3 import zlib -ledmatrix_1 = b'FRAKDEAM1100000000' # POC 1 -ledmatrix_2 = b'FRAKDEBZ4100000000' # EVT 1, config 1 -ledmatrix_3 = b'FRAKDEBZ4200000000' # EVT 1, config 2 (27k resistor) +ledmatrix_1 = b'FRAKDEAM1100000000' # POC 1 +ledmatrix_2 = b'FRAKDEBZ4100000000' # EVT 1, config 1 +ledmatrix_3 = b'FRAKDEBZ4200000000' # EVT 1, config 2 (27k resistor) +ansi_keyboard = b'FRAKDWEN4100000000' # EVT 1, config 1 (US ANSI) +rgb_keyboard = b'FRAKDKEN4100000000' # EVT 1, config 1 (US ANSI) +iso_keyboard = b'FRAKDWEN4200000000' # EVT 1, config 2 (UK ISO) +jis_keyboard = b'FRAKDWEN4J00000000' # EVT 1, config J (JIS) +numpad = b'FRAKDMEN4100000000' # EVT 1, config 1 +macropad = b'FRAKDNEN4100000000' # EVT 1, config 1 # This section is for modifying selected = ledmatrix_2 From cf23d68dd9920879e42b7cfa08a314d59d562673 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 7 Aug 2023 13:34:46 +0800 Subject: [PATCH 3/3] ledmatrix: Update default serialnum to BizLink Signed-off-by: Daniel Schaefer --- ledmatrix/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ledmatrix/src/main.rs b/ledmatrix/src/main.rs index 048cada..506499b 100644 --- a/ledmatrix/src/main.rs +++ b/ledmatrix/src/main.rs @@ -135,10 +135,10 @@ use fl16_inputmodules::serialnum::{device_release, get_serialnum}; // FRA - Framwork // KDE - C1 LED Matrix -// AM - Atemitech -// 00 - Default Configuration +// BZ - BizLink +// 01 - SKU, Default Configuration // 00000000 - Device Identifier -const DEFAULT_SERIAL: &str = "FRAKDEAM0000000000"; +const DEFAULT_SERIAL: &str = "FRAKDEBZ0100000000"; #[entry] fn main() -> ! {