From a29c775663c1fa9ff4e8cef78087a973be17b01a Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 4 May 2018 17:06:16 +0200 Subject: [PATCH] [ion] Encode the serial number in Base64 Also, expose serialNumber() in Ion and keep "copySerialNumber" in Ion::Device. This allows the DFU bootloader to remain .bss-free. --- .../serial_number_controller.cpp | 4 +- apps/settings/sub_controller.cpp | 25 +++------- ion/include/ion.h | 3 +- ion/src/device/Makefile | 1 + ion/src/device/base64.cpp | 48 +++++++++++++++++++ ion/src/device/base64.h | 5 ++ ion/src/device/bench/command/mcu_serial.cpp | 5 +- ion/src/device/device.cpp | 24 ++++------ ion/src/device/device.h | 8 ++++ ion/src/device/usb/Makefile | 1 + ion/src/device/usb/calculator.cpp | 4 +- ion/src/shared/dummy/serial_number.cpp | 4 +- ion/src/simulator/Makefile | 1 + ion/src/simulator/init.cpp | 4 -- 14 files changed, 90 insertions(+), 47 deletions(-) create mode 100644 ion/src/device/base64.cpp create mode 100644 ion/src/device/base64.h diff --git a/apps/hardware_test/serial_number_controller.cpp b/apps/hardware_test/serial_number_controller.cpp index c690517a9..ea4501ef0 100644 --- a/apps/hardware_test/serial_number_controller.cpp +++ b/apps/hardware_test/serial_number_controller.cpp @@ -10,9 +10,7 @@ SerialNumberController::SerialNumberController(Responder * parentResponder) : } void SerialNumberController::viewWillAppear() { - static char serialNumber[24]; - Ion::getSerialNumber(serialNumber); - m_barCodeView.setData(serialNumber); + m_barCodeView.setData(Ion::serialNumber()); } bool SerialNumberController::handleEvent(Ion::Events::Event event) { diff --git a/apps/settings/sub_controller.cpp b/apps/settings/sub_controller.cpp index 853f830d8..ae64fc26c 100644 --- a/apps/settings/sub_controller.cpp +++ b/apps/settings/sub_controller.cpp @@ -192,24 +192,13 @@ void SubController::willDisplayCellForIndex(HighlightCell * cell, int index) { } if (m_messageTreeModel->label() == I18n::Message::About) { myCell->setMessageFontSize(KDText::FontSize::Small); - const char * accessoryMessage = nullptr; - char serialNumber[Ion::SerialNumberLength+1]; - switch (index) { - case 0: - accessoryMessage = Ion::softwareVersion(); - break; - case 1: - Ion::getSerialNumber(serialNumber); - accessoryMessage = serialNumber; - break; - case 2: - accessoryMessage = Ion::fccId(); - break; - default: - assert(false); - break; - } - myCell->setAccessoryText(accessoryMessage); + const char * messages[] = { + Ion::softwareVersion(), + Ion::serialNumber(), + Ion::fccId() + }; + assert(index >= 0 && index < 3); + myCell->setAccessoryText(messages[index]); } } diff --git a/ion/include/ion.h b/ion/include/ion.h index b75527ece..3441619f5 100644 --- a/ion/include/ion.h +++ b/ion/include/ion.h @@ -28,8 +28,7 @@ namespace Ion { void msleep(long ms); void usleep(long us); -constexpr static int SerialNumberLength = 24; -void getSerialNumber(char * buffer); +const char * serialNumber(); const char * softwareVersion(); const char * patchLevel(); const char * fccId(); diff --git a/ion/src/device/Makefile b/ion/src/device/Makefile index 342aee480..7d07e02dc 100644 --- a/ion/src/device/Makefile +++ b/ion/src/device/Makefile @@ -15,6 +15,7 @@ objs += $(addprefix ion/src/shared/, \ objs += $(addprefix ion/src/device/, \ backlight.o \ battery.o\ + base64.o\ console.o \ device.o\ display.o\ diff --git a/ion/src/device/base64.cpp b/ion/src/device/base64.cpp new file mode 100644 index 000000000..6b4bb950c --- /dev/null +++ b/ion/src/device/base64.cpp @@ -0,0 +1,48 @@ +namespace Base64 { + +static constexpr char encodeTable[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', +}; + +constexpr char Padding = '='; + +void encode(const unsigned char * input, unsigned int inputLength, char * output) { + unsigned int i, j; + for (i = j = 0; i < inputLength; i++) { + int s = i % 3; /* from 6/gcd(6, 8) */ + + switch (s) { + case 0: + output[j++] = encodeTable[(input[i] >> 2) & 0x3F]; + continue; + case 1: + output[j++] = encodeTable[((input[i-1] & 0x3) << 4) + ((input[i] >> 4) & 0xF)]; + continue; + case 2: + output[j++] = encodeTable[((input[i-1] & 0xF) << 2) + ((input[i] >> 6) & 0x3)]; + output[j++] = encodeTable[input[i] & 0x3F]; + } + } + + /* move back */ + i -= 1; + + /* check the last and add padding */ + if ((i % 3) == 0) { + output[j++] = encodeTable[(input[i] & 0x3) << 4]; + output[j++] = Padding; + output[j++] = Padding; + } else if ((i % 3) == 1) { + output[j++] = encodeTable[(input[i] & 0xF) << 2]; + output[j++] = Padding; + } +} + +} diff --git a/ion/src/device/base64.h b/ion/src/device/base64.h new file mode 100644 index 000000000..b9a4f2852 --- /dev/null +++ b/ion/src/device/base64.h @@ -0,0 +1,5 @@ +namespace Base64 { + +void encode(const unsigned char * input, unsigned int inputLength, char * output); + +} diff --git a/ion/src/device/bench/command/mcu_serial.cpp b/ion/src/device/bench/command/mcu_serial.cpp index d0dbade42..b6703085b 100644 --- a/ion/src/device/bench/command/mcu_serial.cpp +++ b/ion/src/device/bench/command/mcu_serial.cpp @@ -1,5 +1,6 @@ #include "command.h" #include +#include "../../device.h" namespace Ion { namespace Device { @@ -11,8 +12,8 @@ void MCUSerial(const char * input) { reply(sSyntaxError); return; } - char response[11+Ion::SerialNumberLength + 1] = {'M', 'C', 'U', '_', 'S', 'E', 'R', 'I', 'A', 'L', '=', 0}; - Ion::getSerialNumber(response+11); + char response[11 + Ion::Device::SerialNumberLength + 1] = {'M', 'C', 'U', '_', 'S', 'E', 'R', 'I', 'A', 'L', '=', 0}; + Ion::Device::copySerialNumber(response + 11); reply(response); } diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index 03804a86b..229283ff0 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -14,6 +14,7 @@ extern "C" { #include "swd.h" #include "usb.h" #include "bench/bench.h" +#include "base64.h" #define USE_SD_CARD 0 @@ -65,23 +66,18 @@ uint32_t Ion::random() { return result; } - - -static inline char hex(uint8_t d) { - if (d > 9) { - return 'A'+d-10; - } - return '0'+d; +void Ion::Device::copySerialNumber(char * buffer) { + const unsigned char * rawUniqueID = (const unsigned char *)0x1FFF7A10; + Base64::encode(rawUniqueID, 12, buffer); + buffer[SerialNumberLength] = 0; } -void Ion::getSerialNumber(char * buffer) { - uint8_t * rawUniqueID = (uint8_t *)0x1FFF7A10; - for (int i=0; i> 4); - buffer[2*i+1] = hex(d & 0xF); +const char * Ion::serialNumber() { + static char serialNumber[Device::SerialNumberLength + 1] = {0}; + if (serialNumber[0] == 0) { + Device::copySerialNumber(serialNumber); } - buffer[SerialNumberLength] = 0; + return serialNumber; } // Private Ion::Device methods diff --git a/ion/src/device/device.h b/ion/src/device/device.h index 48058c9ef..a94bd8dea 100644 --- a/ion/src/device/device.h +++ b/ion/src/device/device.h @@ -16,6 +16,14 @@ void shutdownPeripherals(); void initClocks(); void shutdownClocks(); +/* The serial number is 96 bits long. That's equal to 16 digits in base 64. We + * expose a convenient "copySerialNumber" routine which can be called without + * using a static variable (and therefore without a .bss section). This is used + * in the RAM'ed DFU bootloader. */ +constexpr static int SerialNumberLength = 16; +void copySerialNumber(char * buffer); + + /* Pin | Role | Mode | Function * -----+-------------------+-----------------------+---------- * PA0 | Battery sensing | | diff --git a/ion/src/device/usb/Makefile b/ion/src/device/usb/Makefile index a26bc2931..4e69c74ce 100644 --- a/ion/src/device/usb/Makefile +++ b/ion/src/device/usb/Makefile @@ -45,6 +45,7 @@ dfu_objs += ion/src/device/usb/boot.o dfu_objs += ion/src/device/keyboard.o dfu_objs += ion/src/device/device.o dfu_objs += ion/src/device/usb.o +dfu_objs += ion/src/device/base64.o ion/src/device/usb/dfu.elf: LDFLAGS = --gc-sections -T ion/src/device/usb/dfu.ld ion/src/device/usb/dfu.elf: $(usb_objs) $(dfu_objs) diff --git a/ion/src/device/usb/calculator.cpp b/ion/src/device/usb/calculator.cpp index 88a6415d6..e95888c5c 100644 --- a/ion/src/device/usb/calculator.cpp +++ b/ion/src/device/usb/calculator.cpp @@ -9,8 +9,8 @@ namespace USB { namespace Device { void Calculator::PollAndReset(bool exitWithKeyboard) { - char serialNumber[Ion::SerialNumberLength+1]; - Ion::getSerialNumber(serialNumber); + char serialNumber[Ion::Device::SerialNumberLength+1]; + Ion::Device::copySerialNumber(serialNumber); Calculator c(serialNumber); /* Leave DFU mode if the Back key is pressed, the calculator unplugged or the diff --git a/ion/src/shared/dummy/serial_number.cpp b/ion/src/shared/dummy/serial_number.cpp index 6de02c13b..fd0c5deac 100644 --- a/ion/src/shared/dummy/serial_number.cpp +++ b/ion/src/shared/dummy/serial_number.cpp @@ -1,5 +1,5 @@ #include -void Ion::getSerialNumber(char * buffer) { - strlcpy(buffer, "000000000000000000000000", Ion::SerialNumberLength+1); +const char * Ion::serialNumber() { + return "000000000000"; } diff --git a/ion/src/simulator/Makefile b/ion/src/simulator/Makefile index a60779a7f..9f73f59b1 100644 --- a/ion/src/simulator/Makefile +++ b/ion/src/simulator/Makefile @@ -17,6 +17,7 @@ objs += $(addprefix ion/src/shared/, \ dummy/backlight.o \ dummy/battery.o \ dummy/fcc_id.o \ + dummy/serial_number.o \ dummy/usb.o \ ) diff --git a/ion/src/simulator/init.cpp b/ion/src/simulator/init.cpp index eb0b85c19..d20630b14 100644 --- a/ion/src/simulator/init.cpp +++ b/ion/src/simulator/init.cpp @@ -116,7 +116,3 @@ void Ion::msleep(long ms) { } } } - -void Ion::getSerialNumber(char * buffer) { - strlcpy(buffer, "Simulator", Ion::SerialNumberLength+1); -}