[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.
This commit is contained in:
Romain Goyet
2018-05-04 17:06:16 +02:00
committed by Ecco
parent 11ae2da6c5
commit a29c775663
14 changed files with 90 additions and 47 deletions

View File

@@ -10,9 +10,7 @@ SerialNumberController::SerialNumberController(Responder * parentResponder) :
} }
void SerialNumberController::viewWillAppear() { void SerialNumberController::viewWillAppear() {
static char serialNumber[24]; m_barCodeView.setData(Ion::serialNumber());
Ion::getSerialNumber(serialNumber);
m_barCodeView.setData(serialNumber);
} }
bool SerialNumberController::handleEvent(Ion::Events::Event event) { bool SerialNumberController::handleEvent(Ion::Events::Event event) {

View File

@@ -192,24 +192,13 @@ void SubController::willDisplayCellForIndex(HighlightCell * cell, int index) {
} }
if (m_messageTreeModel->label() == I18n::Message::About) { if (m_messageTreeModel->label() == I18n::Message::About) {
myCell->setMessageFontSize(KDText::FontSize::Small); myCell->setMessageFontSize(KDText::FontSize::Small);
const char * accessoryMessage = nullptr; const char * messages[] = {
char serialNumber[Ion::SerialNumberLength+1]; Ion::softwareVersion(),
switch (index) { Ion::serialNumber(),
case 0: Ion::fccId()
accessoryMessage = Ion::softwareVersion(); };
break; assert(index >= 0 && index < 3);
case 1: myCell->setAccessoryText(messages[index]);
Ion::getSerialNumber(serialNumber);
accessoryMessage = serialNumber;
break;
case 2:
accessoryMessage = Ion::fccId();
break;
default:
assert(false);
break;
}
myCell->setAccessoryText(accessoryMessage);
} }
} }

View File

@@ -28,8 +28,7 @@ namespace Ion {
void msleep(long ms); void msleep(long ms);
void usleep(long us); void usleep(long us);
constexpr static int SerialNumberLength = 24; const char * serialNumber();
void getSerialNumber(char * buffer);
const char * softwareVersion(); const char * softwareVersion();
const char * patchLevel(); const char * patchLevel();
const char * fccId(); const char * fccId();

View File

@@ -15,6 +15,7 @@ objs += $(addprefix ion/src/shared/, \
objs += $(addprefix ion/src/device/, \ objs += $(addprefix ion/src/device/, \
backlight.o \ backlight.o \
battery.o\ battery.o\
base64.o\
console.o \ console.o \
device.o\ device.o\
display.o\ display.o\

48
ion/src/device/base64.cpp Normal file
View File

@@ -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;
}
}
}

5
ion/src/device/base64.h Normal file
View File

@@ -0,0 +1,5 @@
namespace Base64 {
void encode(const unsigned char * input, unsigned int inputLength, char * output);
}

View File

@@ -1,5 +1,6 @@
#include "command.h" #include "command.h"
#include <ion.h> #include <ion.h>
#include "../../device.h"
namespace Ion { namespace Ion {
namespace Device { namespace Device {
@@ -11,8 +12,8 @@ void MCUSerial(const char * input) {
reply(sSyntaxError); reply(sSyntaxError);
return; return;
} }
char response[11+Ion::SerialNumberLength + 1] = {'M', 'C', 'U', '_', 'S', 'E', 'R', 'I', 'A', 'L', '=', 0}; char response[11 + Ion::Device::SerialNumberLength + 1] = {'M', 'C', 'U', '_', 'S', 'E', 'R', 'I', 'A', 'L', '=', 0};
Ion::getSerialNumber(response+11); Ion::Device::copySerialNumber(response + 11);
reply(response); reply(response);
} }

View File

@@ -14,6 +14,7 @@ extern "C" {
#include "swd.h" #include "swd.h"
#include "usb.h" #include "usb.h"
#include "bench/bench.h" #include "bench/bench.h"
#include "base64.h"
#define USE_SD_CARD 0 #define USE_SD_CARD 0
@@ -65,23 +66,18 @@ uint32_t Ion::random() {
return result; return result;
} }
void Ion::Device::copySerialNumber(char * buffer) {
const unsigned char * rawUniqueID = (const unsigned char *)0x1FFF7A10;
static inline char hex(uint8_t d) { Base64::encode(rawUniqueID, 12, buffer);
if (d > 9) { buffer[SerialNumberLength] = 0;
return 'A'+d-10;
}
return '0'+d;
} }
void Ion::getSerialNumber(char * buffer) { const char * Ion::serialNumber() {
uint8_t * rawUniqueID = (uint8_t *)0x1FFF7A10; static char serialNumber[Device::SerialNumberLength + 1] = {0};
for (int i=0; i<SerialNumberLength/2; i++) { if (serialNumber[0] == 0) {
uint8_t d = *rawUniqueID++; Device::copySerialNumber(serialNumber);
buffer[2*i] = hex(d >> 4);
buffer[2*i+1] = hex(d & 0xF);
} }
buffer[SerialNumberLength] = 0; return serialNumber;
} }
// Private Ion::Device methods // Private Ion::Device methods

View File

@@ -16,6 +16,14 @@ void shutdownPeripherals();
void initClocks(); void initClocks();
void shutdownClocks(); 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 /* Pin | Role | Mode | Function
* -----+-------------------+-----------------------+---------- * -----+-------------------+-----------------------+----------
* PA0 | Battery sensing | | * PA0 | Battery sensing | |

View File

@@ -45,6 +45,7 @@ dfu_objs += ion/src/device/usb/boot.o
dfu_objs += ion/src/device/keyboard.o dfu_objs += ion/src/device/keyboard.o
dfu_objs += ion/src/device/device.o dfu_objs += ion/src/device/device.o
dfu_objs += ion/src/device/usb.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: LDFLAGS = --gc-sections -T ion/src/device/usb/dfu.ld
ion/src/device/usb/dfu.elf: $(usb_objs) $(dfu_objs) ion/src/device/usb/dfu.elf: $(usb_objs) $(dfu_objs)

View File

@@ -9,8 +9,8 @@ namespace USB {
namespace Device { namespace Device {
void Calculator::PollAndReset(bool exitWithKeyboard) { void Calculator::PollAndReset(bool exitWithKeyboard) {
char serialNumber[Ion::SerialNumberLength+1]; char serialNumber[Ion::Device::SerialNumberLength+1];
Ion::getSerialNumber(serialNumber); Ion::Device::copySerialNumber(serialNumber);
Calculator c(serialNumber); Calculator c(serialNumber);
/* Leave DFU mode if the Back key is pressed, the calculator unplugged or the /* Leave DFU mode if the Back key is pressed, the calculator unplugged or the

View File

@@ -1,5 +1,5 @@
#include <ion.h> #include <ion.h>
void Ion::getSerialNumber(char * buffer) { const char * Ion::serialNumber() {
strlcpy(buffer, "000000000000000000000000", Ion::SerialNumberLength+1); return "000000000000";
} }

View File

@@ -17,6 +17,7 @@ objs += $(addprefix ion/src/shared/, \
dummy/backlight.o \ dummy/backlight.o \
dummy/battery.o \ dummy/battery.o \
dummy/fcc_id.o \ dummy/fcc_id.o \
dummy/serial_number.o \
dummy/usb.o \ dummy/usb.o \
) )

View File

@@ -116,7 +116,3 @@ void Ion::msleep(long ms) {
} }
} }
} }
void Ion::getSerialNumber(char * buffer) {
strlcpy(buffer, "Simulator", Ion::SerialNumberLength+1);
}