diff --git a/board/flasher.h b/board/flasher.h index 32715761..f1a4f645 100644 --- a/board/flasher.h +++ b/board/flasher.h @@ -41,6 +41,13 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { resp[1] = 0xff; } break; + // **** 0xc3: fetch MCU UID + case 0xc3: + #ifdef UID_BASE + (void)memcpy(resp, ((uint8_t *)UID_BASE), 12); + resp_len = 12; + #endif + break; // **** 0xd0: fetch serial number case 0xd0: #ifndef STM32F2 diff --git a/board/main_comms.h b/board/main_comms.h index 3ae04147..2ee65e1d 100644 --- a/board/main_comms.h +++ b/board/main_comms.h @@ -147,7 +147,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { resp[0] = hw_type; resp_len = 1; break; - // **** 0xd0: fetch serial number + // **** 0xc2: CAN health stats case 0xc2: COMPILE_TIME_ASSERT(sizeof(can_health_t) <= USBPACKET_MAX_SIZE); if (req->param1 < 3U) { @@ -160,6 +160,12 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { (void)memcpy(resp, &can_health[req->param1], resp_len); } break; + // **** 0xc3: fetch MCU UID + case 0xc3: + (void)memcpy(resp, ((uint8_t *)UID_BASE), 12); + resp_len = 12; + break; + // **** 0xd0: fetch serial (aka the provisioned dongle ID) case 0xd0: // addresses are OTP if (req->param1 == 1U) { diff --git a/board/provision.h b/board/provision.h index 84217944..e56205bf 100644 --- a/board/provision.h +++ b/board/provision.h @@ -1,3 +1,6 @@ +// this is where we manage the dongle ID assigned during our +// manufacturing. aside from this, there's a UID for the MCU + #define PROVISION_CHUNK_LEN 0x20 void get_provision_chunk(uint8_t *resp) { diff --git a/python/__init__.py b/python/__init__.py index e98701b8..30de914a 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -5,6 +5,7 @@ import time import usb1 import struct import hashlib +import binascii import datetime import traceback import warnings @@ -588,14 +589,28 @@ class Panda: return self.get_type() in Panda.INTERNAL_DEVICES def get_serial(self): + """ + Returns the comma-issued dongle ID from our provisioning + """ dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd0, 0, 0, 0x20) hashsig, calc_hash = dat[0x1c:], hashlib.sha1(dat[0:0x1c]).digest()[0:4] assert(hashsig == calc_hash) return [dat[0:0x10].decode("utf8"), dat[0x10:0x10 + 10].decode("utf8")] def get_usb_serial(self): + """ + Returns the serial number reported from the USB descriptor; + matches the MCU UID + """ return self._serial + def get_uid(self): + """ + Returns the UID from the MCU + """ + dat = self._handle.controlRead(Panda.REQUEST_IN, 0xc3, 0, 0, 12) + return binascii.hexlify(dat).decode() + def get_secret(self): return self._handle.controlRead(Panda.REQUEST_IN, 0xd0, 1, 0, 0x10) diff --git a/tests/hitl/2_health.py b/tests/hitl/2_health.py index a5389733..19b3e469 100644 --- a/tests/hitl/2_health.py +++ b/tests/hitl/2_health.py @@ -53,6 +53,10 @@ def test_hw_type(p): mcu_type = p.get_mcu_type() assert mcu_type is not None + app_uid = p.get_uid() + usb_serial = p.get_usb_serial() + assert app_uid == usb_serial + p.reset(enter_bootstub=True, reconnect=True) p.close() time.sleep(3) @@ -60,6 +64,7 @@ def test_hw_type(p): assert pp.bootstub assert pp.get_type() == hw_type, "Bootstub and app hw type mismatch" assert pp.get_mcu_type() == mcu_type, "Bootstub and app MCU type mismatch" + assert pp.get_uid() == app_uid @test_all_pandas