Skip to content

Commit a153433

Browse files
Merge pull request #61 from FrameworkComputer/serialnum-crc
2 parents 22f2257 + cf23d68 commit a153433

File tree

9 files changed

+137
-17
lines changed

9 files changed

+137
-17
lines changed

Cargo.lock

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

b1display/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ fn main() -> ! {
114114
let mut serial = SerialPort::new(&usb_bus);
115115

116116
let serialnum = if let Some(serialnum) = get_serialnum() {
117-
serialnum
117+
serialnum.serialnum
118118
} else {
119119
DEFAULT_SERIAL
120120
};

c1minimal/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ fn main() -> ! {
103103
let mut serial = SerialPort::new(&usb_bus);
104104

105105
let serialnum = if let Some(serialnum) = get_serialnum() {
106-
serialnum
106+
serialnum.serialnum
107107
} else {
108108
DEFAULT_SERIAL
109109
};

fl16-inputmodules/Cargo.toml

+5-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ name = "fl16-inputmodules"
44
version = "0.1.5"
55

66
[dependencies]
7+
crc = "3.0"
78
cortex-m = "0.7"
89
cortex-m-rt = "0.7.3"
910
embedded-hal = { version = "0.2.7", features = ["unproven"] }
@@ -15,7 +16,7 @@ defmt-rtt = "0.4"
1516
rp2040-panic-usb-boot = "0.5.0"
1617

1718
# Not using an external BSP, we've got the Framework Laptop 16 BSPs locally in this crate
18-
rp2040-hal = { version="0.8", features=["rt", "critical-section-impl"] }
19+
rp2040-hal = { version = "0.8", features = ["rt", "critical-section-impl"] }
1920
rp2040-boot2 = "0.3"
2021

2122
# USB Serial
@@ -43,6 +44,6 @@ ws2812-pio = { version = "0.6.0", optional = true }
4344

4445
[features]
4546
default = []
46-
ledmatrix = [ "is31fl3741" ]
47-
b1display = [ "st7306", "embedded-graphics", "tinybmp" ]
48-
c1minimal = ["smart-leds", "ws2812-pio" ]
47+
ledmatrix = ["is31fl3741"]
48+
b1display = ["st7306", "embedded-graphics", "tinybmp"]
49+
c1minimal = ["smart-leds", "ws2812-pio"]

fl16-inputmodules/src/serialnum.rs

+34-7
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,43 @@ const FLASH_OFFSET: usize = 0x10000000;
33
const LAST_4K_BLOCK: usize = 0xff000;
44
const SERIALNUM_LEN: usize = 18;
55

6-
pub fn get_serialnum() -> Option<&'static str> {
6+
#[repr(packed)]
7+
pub struct SerialnumStructRaw {
8+
sn_rev: u8,
9+
serialnum: [u8; SERIALNUM_LEN],
10+
crc32: [u8; 4],
11+
}
12+
13+
pub struct SerialnumStruct {
14+
pub serialnum: &'static str,
15+
}
16+
17+
pub fn get_serialnum() -> Option<SerialnumStruct> {
718
// Flash is mapped into memory, just read it from there
819
let ptr: *const u8 = (FLASH_OFFSET + LAST_4K_BLOCK) as *const u8;
9-
unsafe {
10-
let slice: &[u8] = core::slice::from_raw_parts(ptr, SERIALNUM_LEN);
11-
if slice[0] == 0xFF || slice[0] == 0x00 {
12-
return None;
13-
}
14-
core::str::from_utf8(slice).ok()
20+
let sn_raw_ptr = ptr as *const SerialnumStructRaw;
21+
let sn_raw = unsafe { sn_raw_ptr.as_ref()? };
22+
23+
// Only rev 1 supported
24+
if sn_raw.sn_rev != 1 {
25+
return None;
1526
}
27+
28+
let crc: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);
29+
let mut digest = crc.digest();
30+
digest.update(&[sn_raw.sn_rev]);
31+
digest.update(&sn_raw.serialnum);
32+
let calc_checksum = digest.finalize();
33+
34+
let actual_checksum = u32::from_le_bytes(sn_raw.crc32);
35+
// Checksum invalid, serial fall back to default serial number
36+
if calc_checksum != actual_checksum {
37+
return None;
38+
}
39+
40+
Some(SerialnumStruct {
41+
serialnum: core::str::from_utf8(&sn_raw.serialnum).ok()?,
42+
})
1643
}
1744

1845
/// Get the firmware version in a format for USB Device Release

flash_layout.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Flash Layout
2+
3+
The flash is 1MB large and consists of 256 4K blocks.
4+
The last block is used to store the serial number.
5+
6+
###### LED Matrix
7+
8+
| Start | End | Size | Name |
9+
|----------|----------|---------------|--------------------|
10+
| 0x000000 | Dynamic | Roughly 40K | Firmware |
11+
| TBD | 0x0FF000 | TBD | Persistent Storage |
12+
| 0x0FF000 | 0x100000 | 0x1000 (4K) | Serial Number |
13+
14+
###### QMK Keyboards
15+
16+
| Start | End | Size | Name |
17+
|----------|----------|---------------|--------------------|
18+
| 0x000000 | Dynamic | Roughly 60K | Firmware |
19+
| 0xef000 | 0x0FF000 | 0x10000 (16K) | Persistent Storage |
20+
| 0x0FF000 | 0x100000 | 0x01000 (4K) | Serial Number |
21+
22+
## Serial Number
23+
24+
- 1 byte serial number revision (== 1)
25+
- 18 bytes serial number
26+
- 1 byte hardware revision
27+
- 4 byte CRC checksum over serial number (CRC32B, same as Python's `zlib.crc32()`)
28+
29+
Hardware Revisions:
30+
31+
- B1 Display
32+
- 1 First Prototype, very early prototype
33+
- LED Matrix
34+
- 1 First Prototype (ATC)
35+
- 2 Second Prototype (BizLink)
36+
- 3 Third Prototype, 27k Resistor
37+
- Keyboard, Numpad, Macropad
38+
- 1 First Prototype

ledmatrix/src/main.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,10 @@ use fl16_inputmodules::serialnum::{device_release, get_serialnum};
135135

136136
// FRA - Framwork
137137
// KDE - C1 LED Matrix
138-
// AM - Atemitech
139-
// 00 - Default Configuration
138+
// BZ - BizLink
139+
// 01 - SKU, Default Configuration
140140
// 00000000 - Device Identifier
141-
const DEFAULT_SERIAL: &str = "FRAKDEAM0000000000";
141+
const DEFAULT_SERIAL: &str = "FRAKDEBZ0100000000";
142142

143143
#[entry]
144144
fn main() -> ! {
@@ -184,7 +184,7 @@ fn main() -> ! {
184184
let mut serial = SerialPort::new(&usb_bus);
185185

186186
let serialnum = if let Some(serialnum) = get_serialnum() {
187-
serialnum
187+
serialnum.serialnum
188188
} else {
189189
DEFAULT_SERIAL
190190
};

scripts/serial.py

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python3
2+
import zlib
3+
4+
ledmatrix_1 = b'FRAKDEAM1100000000' # POC 1
5+
ledmatrix_2 = b'FRAKDEBZ4100000000' # EVT 1, config 1
6+
ledmatrix_3 = b'FRAKDEBZ4200000000' # EVT 1, config 2 (27k resistor)
7+
ansi_keyboard = b'FRAKDWEN4100000000' # EVT 1, config 1 (US ANSI)
8+
rgb_keyboard = b'FRAKDKEN4100000000' # EVT 1, config 1 (US ANSI)
9+
iso_keyboard = b'FRAKDWEN4200000000' # EVT 1, config 2 (UK ISO)
10+
jis_keyboard = b'FRAKDWEN4J00000000' # EVT 1, config J (JIS)
11+
numpad = b'FRAKDMEN4100000000' # EVT 1, config 1
12+
macropad = b'FRAKDNEN4100000000' # EVT 1, config 1
13+
14+
# This section is for modifying
15+
selected = ledmatrix_2
16+
year = b'3' # 2023
17+
week = b'01'
18+
day = b'1'
19+
part_sn = b'0001'
20+
21+
config = selected[8:10]
22+
serial_rev = b'\x01'
23+
snum = selected
24+
print(serial_rev + snum)
25+
snum = snum[0:8] + config + year + week + day + part_sn
26+
27+
checksum = zlib.crc32(serial_rev + snum)
28+
print(serial_rev + snum)
29+
30+
print('Checksum:', hex(zlib.crc32(snum)))
31+
print('Digest: ', hex(checksum))
32+
with open('serial.bin', 'wb') as f:
33+
f.write(serial_rev)
34+
f.write(snum)
35+
f.write(checksum.to_bytes(4, 'little'))

scripts/serial.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
./serial.py
3+
../qmk_firmware/util/uf2conv.py serial.bin -o serial.uf2 -b 0x100ff000 -f rp2040 --convert

0 commit comments

Comments
 (0)