Skip to content

Commit

Permalink
Merge pull request #61 from FrameworkComputer/serialnum-crc
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnAZoidberg authored Aug 8, 2023
2 parents 22f2257 + cf23d68 commit a153433
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 17 deletions.
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion b1display/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down
2 changes: 1 addition & 1 deletion c1minimal/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down
9 changes: 5 additions & 4 deletions fl16-inputmodules/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand All @@ -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
Expand Down Expand Up @@ -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"]
41 changes: 34 additions & 7 deletions fl16-inputmodules/src/serialnum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<SerialnumStruct> {
// 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<u32> = crc::Crc::<u32>::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
Expand Down
38 changes: 38 additions & 0 deletions flash_layout.md
Original file line number Diff line number Diff line change
@@ -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
8 changes: 4 additions & 4 deletions ledmatrix/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() -> ! {
Expand Down Expand Up @@ -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
};
Expand Down
35 changes: 35 additions & 0 deletions scripts/serial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/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)
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
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'))
3 changes: 3 additions & 0 deletions scripts/serial.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
./serial.py
../qmk_firmware/util/uf2conv.py serial.bin -o serial.uf2 -b 0x100ff000 -f rp2040 --convert

0 comments on commit a153433

Please sign in to comment.