From 1373e62ba05d518d772d3446367cd3c3353fb73a Mon Sep 17 00:00:00 2001 From: Rob Riggs Date: Mon, 29 Oct 2018 14:06:52 -0500 Subject: [PATCH] Set serial number in BM78 DIS and USB descriptor, and return it via KISS HW commands. --- Inc/main.h | 1 + Src/main.c | 9 +++++-- Src/usbd_desc.c | 2 +- TNC/KissHardware.cpp | 17 ++++++++++--- TNC/KissHardware.hpp | 9 +++++-- TNC/base64.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++ TNC/base64.h | 38 +++++++++++++++++++++++++++++ TNC/bm78.cpp | 21 ++++++++++++++++ 8 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 TNC/base64.cpp create mode 100644 TNC/base64.h diff --git a/Inc/main.h b/Inc/main.h index 6c2ccba..7d4006a 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -157,6 +157,7 @@ extern int reset_requested; extern char serial_number[25]; +extern char serial_number_64[17]; #define CxxErrorHandler() _Error_Handler(const_cast(__FILE__), __LINE__) diff --git a/Src/main.c b/Src/main.c index 2060032..f495529 100644 --- a/Src/main.c +++ b/Src/main.c @@ -58,6 +58,7 @@ #include "PortInterface.h" #include "LEDIndicator.h" #include "bm78.h" +#include "base64.h" /* USER CODE END Includes */ @@ -143,6 +144,7 @@ osStaticTimerDef_t beaconTimer4ControlBlock; int reset_requested = 0; char serial_number[25]; +char serial_number_64[17] = {0}; /* USER CODE END PV */ @@ -259,8 +261,6 @@ void power_down_vdd() { __HAL_RCC_GPIOB_CLK_ENABLE(); - GPIO_InitTypeDef GPIO_InitStruct; - HAL_GPIO_WritePin(VDD_EN_GPIO_Port, VDD_EN_Pin, GPIO_PIN_RESET); for (int i = 0; i < 4800; ++i) asm volatile("nop"); } @@ -371,6 +371,11 @@ int main(void) uint32_t* uid = (uint32_t*) UID_BASE; snprintf(serial_number, sizeof(serial_number), "%08lx%08lx%08lx", uid[0], uid[1], uid[2]); + { + uint32_t len = 17; + base64encode((const uint8_t*) UID_BASE, 12, serial_number_64, &len); + } + // The Bluetooth module is powered on during MX_GPIO_Init(). BT_CMD // has a weak pull-up on the BT module and is in OD mode. Pull the // pin low during boot to enter Bluetooth programming mode. Here the diff --git a/Src/usbd_desc.c b/Src/usbd_desc.c index 2ebe5fc..6565548 100644 --- a/Src/usbd_desc.c +++ b/Src/usbd_desc.c @@ -333,7 +333,7 @@ uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) } else { - USBD_GetString((uint8_t *)USBD_SERIALNUMBER_STRING_FS, USBD_StrDesc, length); + USBD_GetString((uint8_t *)serial_number_64, USBD_StrDesc, length); } return USBD_StrDesc; } diff --git a/TNC/KissHardware.cpp b/TNC/KissHardware.cpp index 8208e50..ebdce70 100644 --- a/TNC/KissHardware.cpp +++ b/TNC/KissHardware.cpp @@ -15,7 +15,7 @@ extern I2C_HandleTypeDef hi2c1; namespace mobilinkd { namespace tnc { namespace kiss { -const char FIRMWARE_VERSION[] = "0.8.7"; +const char FIRMWARE_VERSION[] = "0.8.8"; const char HARDWARE_VERSION[] = "Mobilinkd TNC3 2.1.1"; Hardware& settings() @@ -293,6 +293,11 @@ void Hardware::handle_request(hdlc::IoFrame* frame) { reply(hardware::GET_HARDWARE_VERSION, (uint8_t*) HARDWARE_VERSION, sizeof(HARDWARE_VERSION) - 1); break; + case hardware::GET_SERIAL_NUMBER: + DEBUG("GET_SERIAL_NUMBER"); + reply(hardware::GET_SERIAL_NUMBER, (uint8_t*) serial_number_64, + sizeof(serial_number_64) - 1); + break; case hardware::SET_PTT_CHANNEL: DEBUG("SET_PTT_CHANNEL"); @@ -343,7 +348,9 @@ void Hardware::handle_request(hdlc::IoFrame* frame) { case hardware::GET_CAPABILITIES: DEBUG("GET_CAPABILITIES"); - reply16(hardware::GET_CAPABILITIES, hardware::CAP_EEPROM_SAVE|hardware::CAP_BATTERY_LEVEL); + reply16(hardware::GET_CAPABILITIES, + hardware::CAP_EEPROM_SAVE|hardware::CAP_BATTERY_LEVEL| + hardware::CAP_ADJUST_INPUT); break; case hardware::GET_ALL_VALUES: @@ -359,6 +366,8 @@ void Hardware::handle_request(hdlc::IoFrame* frame) { sizeof(FIRMWARE_VERSION) - 1); reply(hardware::GET_HARDWARE_VERSION, (uint8_t*) HARDWARE_VERSION, sizeof(HARDWARE_VERSION) - 1); + reply(hardware::GET_SERIAL_NUMBER, (uint8_t*) serial_number_64, + sizeof(serial_number_64) - 1); reply8(hardware::GET_USB_POWER_OFF, options & KISS_OPTION_VIN_POWER_OFF ? 0 : 1); reply8(hardware::GET_USB_POWER_ON, options & KISS_OPTION_VIN_POWER_ON ? 0 : 1); reply8(hardware::GET_OUTPUT_GAIN, output_gain); @@ -372,7 +381,9 @@ void Hardware::handle_request(hdlc::IoFrame* frame) { reply8(hardware::GET_DUPLEX, duplex); reply8(hardware::GET_PTT_CHANNEL, options & KISS_OPTION_PTT_SIMPLEX ? 0 : 1); - reply16(hardware::GET_CAPABILITIES, hardware::CAP_EEPROM_SAVE|hardware::CAP_BATTERY_LEVEL); + reply16(hardware::GET_CAPABILITIES, + hardware::CAP_EEPROM_SAVE|hardware::CAP_BATTERY_LEVEL| + hardware::CAP_ADJUST_INPUT); reply16(hardware::GET_MIN_INPUT_GAIN, 0); reply16(hardware::GET_MAX_INPUT_GAIN, 4); diff --git a/TNC/KissHardware.hpp b/TNC/KissHardware.hpp index 1f7ecb4..fb85220 100644 --- a/TNC/KissHardware.hpp +++ b/TNC/KissHardware.hpp @@ -43,11 +43,12 @@ constexpr const uint16_t CAP_BT_NAME_CHANGE = 0x4000; constexpr const uint16_t CAP_BT_PIN_CHANGE = 0x8000; constexpr const uint16_t CAP_VERBOSE_ERROR = 0x0001; constexpr const uint16_t CAP_EEPROM_SAVE = 0x0002; +constexpr const uint16_t CAP_ADJUST_INPUT = 0x0004; // Auto-adjust input levels. constexpr const uint8_t SAVE = 0; // Save settings to EEPROM. constexpr const uint8_t SET_OUTPUT_GAIN = 1; constexpr const uint8_t SET_INPUT_GAIN = 2; -constexpr const uint8_t SET_SQUELCH_LEVEL = 3; +constexpr const uint8_t SET_SQUELCH_LEVEL = 3; // deprecated. constexpr const uint8_t POLL_INPUT_LEVEL = 4; constexpr const uint8_t STREAM_INPUT_LEVEL = 5; constexpr const uint8_t GET_BATTERY_LEVEL = 6; @@ -91,10 +92,14 @@ constexpr const uint8_t GET_DUPLEX = 37; constexpr const uint8_t GET_FIRMWARE_VERSION = 40; constexpr const uint8_t GET_HARDWARE_VERSION = 41; constexpr const uint8_t SAVE_EEPROM_SETTINGS = 42; -constexpr const uint8_t ADJUST_INPUT_LEVELS = 43; +constexpr const uint8_t ADJUST_INPUT_LEVELS = 43; // Auto-adjust levels. constexpr const uint8_t POLL_INPUT_TWIST = 44; constexpr const uint8_t STREAM_AVG_INPUT_TWIST = 45; constexpr const uint8_t STREAM_INPUT_TWIST = 46; +constexpr const uint8_t GET_SERIAL_NUMBER = 47; +constexpr const uint8_t GET_MAC_ADDRESS = 48; +constexpr const uint8_t GET_DATETIME = 49; +constexpr const uint8_t SET_DATETIME = 50; constexpr const uint8_t SET_BLUETOOTH_NAME = 65; constexpr const uint8_t GET_BLUETOOTH_NAME = 66; diff --git a/TNC/base64.cpp b/TNC/base64.cpp new file mode 100644 index 0000000..09f1e74 --- /dev/null +++ b/TNC/base64.cpp @@ -0,0 +1,57 @@ +// Copyright 2018 Rob Riggs +// All rights reserved. + +#include "base64.h" +#include "assert.h" + +namespace { +const char alphabet[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +} + +uint32_t base64encode(const uint8_t* src, uint32_t src_len, char* dest, + uint32_t* dest_len) +{ + uint32_t expected = ((src_len * 4) + 2) / 3; + uint32_t dpos = 0; + uint8_t b1, b2, b3, b4; + for (uint32_t i = 0; i < src_len; i += 3) + { + if (dpos == *dest_len) return expected; + b1 = src[i] >> 2; + b2 = ((src[i] & 0x3) << 4); + dest[dpos++] = alphabet[b1]; + + if (dpos == *dest_len) return expected; + if (i + 1 == src_len) + { + dest[dpos++] = alphabet[b2]; + break; + } + else + { + b2 |= (src[i + 1] >> 4); + dest[dpos++] = alphabet[b2]; + b3 = (src[i + 1] & 0x0F) << 2; + } + + if (dpos == *dest_len) return expected; + if (i + 2 == src_len) + { + dest[dpos++] = alphabet[b3]; + break; + } + else + { + b3 |= src[i + 2] >> 6; + dest[dpos++] = alphabet[b3]; + b4 = src[i + 2] & 0x3F; + } + + if (dpos == *dest_len) return expected; + dest[dpos++] = alphabet[b4]; + } + *dest_len = dpos; + assert(*dest_len == expected); + return expected; +} diff --git a/TNC/base64.h b/TNC/base64.h new file mode 100644 index 0000000..9e6649e --- /dev/null +++ b/TNC/base64.h @@ -0,0 +1,38 @@ +// Copyright 2018 Rob Riggs +// All rights reserved. + +#ifndef MOBILINKD__TNC__BASE64_H_ +#define MOBILINKD__TNC__BASE64_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Base64 encode binary data from src, storing the result in dest. The + * input value of dest_len limits the length of the string which will be + * written to dest. If this value is not >= 4/3 * src_len, the output + * string will be truncated. The amount written will be returned in + * dest_len (in this case in==out) and the amount that would have been + * written is returned. + * + * If the return value and the value returned in dest_len are different, + * dest did not contain enough space to fully encode the result. + * + * @param src is the binary data to be base64 encoded. + * @param src_len is the length of the binary data to encode. + * @param dest is the destination buffer to contain the encoded string. + * @param[in,out] dest_len on input is the size of the dest buffer and on + * output is the number of characters written to dest. + * @return the length of src fully base64 encoded. + */ +uint32_t base64encode(const uint8_t* src, uint32_t src_len, char* dest, + uint32_t* dest_len); + +#ifdef __cplusplus +} +#endif + +#endif // MOBILINKD__TNC__BASE64_H_ diff --git a/TNC/bm78.cpp b/TNC/bm78.cpp index 4569a12..addc5af 100644 --- a/TNC/bm78.cpp +++ b/TNC/bm78.cpp @@ -210,6 +210,26 @@ bool write_eeprom() return result; } +bool write_serial() +{ + uint8_t cmd[] = {0x01, 0x27, 0xfc, 0x13, 02, 0x42, 0x10}; + + if (HAL_UART_Transmit(&huart3, cmd, sizeof(cmd), 1000) != HAL_OK) + { + ERROR("%s transmit header failed", __PRETTY_FUNCTION__); + return false; + } + + if (HAL_UART_Transmit(&huart3, reinterpret_cast(serial_number_64), + 16, 1000) != HAL_OK) + { + ERROR("%s transmit data failed", __PRETTY_FUNCTION__); + return false; + } + + return parse_write_result(__PRETTY_FUNCTION__); +} + bool set_name() { uint8_t cmd[] = {0x01, 0x27, 0xfc, 0x13, 0x00, 0x0b, 0x10 @@ -481,6 +501,7 @@ int bm78_initialize() enter_program_mode(); if (!write_eeprom()) result = 1; + else if (!write_serial()) result = 2; exit_program_mode(); #if 1