diff --git a/software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.cpp b/software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.cpp index adf76c2e8..3cf8f61fd 100644 --- a/software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.cpp +++ b/software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.cpp @@ -174,6 +174,110 @@ bool BLESensBox::notify_sys(uint8_t status) return _sensbox_sys.notify(&data, sizeof(sensbox_system_t)) > 0; } +const uint16_t UUID16_SVC_DFU_OTA = 0xFE59; + +const uint8_t UUID128_CHR_DFU_CONTROL[16] = {0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F, + 0x60, 0x4F, 0x15, 0xF3, 0x03, 0x00, 0xC9, 0x8E}; + +extern "C" void bootloader_util_app_start(uint32_t start_addr); + +static uint16_t crc16(const uint8_t *data_p, uint8_t length) +{ + uint8_t x; + uint16_t crc = 0xFFFF; + + while (length--) { + x = crc >> 8 ^ *data_p++; + x ^= x >> 4; + crc = (crc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x << 5)) ^ ((uint16_t)x); + } + return crc; +} + +static void bledfu_control_wr_authorize_cb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_write_t *request) +{ + if ((request->handle == chr->handles().value_handle) && (request->op != BLE_GATTS_OP_PREP_WRITE_REQ) && + (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) && (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) { + BLEConnection *conn = Bluefruit.Connection(conn_hdl); + + ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE}; + + if (!chr->indicateEnabled(conn_hdl)) { + reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR; + sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); + return; + } + + reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); + + enum { START_DFU = 1 }; + if (request->data[0] == START_DFU) { + // Peer data information so that bootloader could re-connect after reboot + typedef struct { + ble_gap_addr_t addr; + ble_gap_irk_t irk; + ble_gap_enc_key_t enc_key; + uint8_t sys_attr[8]; + uint16_t crc16; + } peer_data_t; + + VERIFY_STATIC(offsetof(peer_data_t, crc16) == 60); + + /* Save Peer data + * Peer data address is defined in bootloader linker @0x20007F80 + * - If bonded : save Security information + * - Otherwise : save Address for direct advertising + * + * TODO may force bonded only for security reason + */ + peer_data_t *peer_data = (peer_data_t *)(0x20007F80UL); + varclr(peer_data); + + // Get CCCD + uint16_t sysattr_len = sizeof(peer_data->sys_attr); + sd_ble_gatts_sys_attr_get(conn_hdl, peer_data->sys_attr, &sysattr_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); + + // Get Bond Data or using Address if not bonded + peer_data->addr = conn->getPeerAddr(); + + if (conn->secured()) { + bond_keys_t bkeys; + if (conn->loadBondKey(&bkeys)) { + peer_data->addr = bkeys.peer_id.id_addr_info; + peer_data->irk = bkeys.peer_id.id_info; + peer_data->enc_key = bkeys.own_enc; + } + } + + // Calculate crc + peer_data->crc16 = crc16((uint8_t *)peer_data, offsetof(peer_data_t, crc16)); + + // Initiate DFU Sequence and reboot into DFU OTA mode + Bluefruit.Advertising.restartOnDisconnect(false); + conn->disconnect(); + + NRF_POWER->GPREGRET = 0xB1; + NVIC_SystemReset(); + } + } +} + +BLEDfuSecure::BLEDfuSecure(void) : BLEService(UUID16_SVC_DFU_OTA), _chr_control(UUID128_CHR_DFU_CONTROL) {} + +err_t BLEDfuSecure::begin(void) +{ + // Invoke base class begin() + VERIFY_STATUS(BLEService::begin()); + + _chr_control.setProperties(CHR_PROPS_WRITE | CHR_PROPS_INDICATE); + _chr_control.setMaxLen(23); + _chr_control.setWriteAuthorizeCallback(bledfu_control_wr_authorize_cb); + VERIFY_STATUS(_chr_control.begin()); + + return ERROR_NONE; +} + static unsigned long BLE_Notify_TimeMarker = 0; static unsigned long BLE_SensBox_TimeMarker = 0; @@ -193,6 +297,7 @@ static unsigned long BLE_SensBox_TimeMarker = 0; // BLE Service BLEDfu bledfu; // OTA DFU service +BLEDfuSecure bledfusecure; BLEDis bledis; // device information BLEUart_HM10 bleuart_HM10; // TI UART over BLE #if !defined(EXCLUDE_NUS) @@ -362,7 +467,12 @@ void nRF52_Bluetooth_setup() Bluefruit.Periph.setDisconnectCallback(disconnect_callback); // To be consistent OTA DFU should be added first if it exists - bledfu.begin(); + if (hw_info.model == SOFTRF_MODEL_CARD) { + bledfusecure.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); + bledfusecure.begin(); + } else { + bledfu.begin(); + } // Configure and Start Device Information Service bledis.setManufacturer(nRF52_Device_Manufacturer); diff --git a/software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.h b/software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.h index 4ddcd2bcf..a6c19267b 100644 --- a/software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.h +++ b/software/firmware/source/SoftRF/src/platform/bluetooth/Bluefruit.h @@ -87,4 +87,15 @@ typedef struct { #define isTimeToSensBox() (millis() - BLE_SensBox_TimeMarker > 500) /* 2 Hz */ +class BLEDfuSecure : public BLEService +{ + protected: + BLECharacteristic _chr_control; + + public: + BLEDfuSecure(void); + + virtual err_t begin(void); +}; + extern IODev_ops_t nRF52_Bluetooth_ops; diff --git a/software/firmware/source/SoftRF/src/platform/iomap/Seeed_T1000.h b/software/firmware/source/SoftRF/src/platform/iomap/Seeed_T1000.h index 5e2b42175..52bb66690 100644 --- a/software/firmware/source/SoftRF/src/platform/iomap/Seeed_T1000.h +++ b/software/firmware/source/SoftRF/src/platform/iomap/Seeed_T1000.h @@ -7,9 +7,11 @@ #define SOC_GPIO_PIN_GNSS_T1000_TX _PINNUM(0, 13) // P0.13 #define SOC_GPIO_PIN_GNSS_T1000_PPS SOC_UNUSED_PIN -#define SOC_GPIO_PIN_GNSS_T1000_IRQ _PINNUM(1, 12) // P1.12 -#define SOC_GPIO_PIN_GNSS_T1000_RST _PINNUM(1, 15) // P1.15 active HIGH #define SOC_GPIO_PIN_GNSS_T1000_EN _PINNUM(1, 11) // P1.11 active HIGH +#define SOC_GPIO_PIN_GNSS_T1000_RST _PINNUM(1, 15) // P1.15 active HIGH +#define SOC_GPIO_PIN_GNSS_T1000_VRTC _PINNUM(0, 8) // P0.08 +#define SOC_GPIO_PIN_GNSS_T1000_SINT _PINNUM(1, 12) // P1.12 +#define SOC_GPIO_PIN_GNSS_T1000_RINT _PINNUM(0, 15) // P0.15 /* SPI */ #define SOC_GPIO_PIN_T1000_MOSI _PINNUM(1, 9) // P1.09 diff --git a/software/firmware/source/SoftRF/src/platform/nRF52.cpp b/software/firmware/source/SoftRF/src/platform/nRF52.cpp index fa094ef82..76e44d379 100644 --- a/software/firmware/source/SoftRF/src/platform/nRF52.cpp +++ b/software/firmware/source/SoftRF/src/platform/nRF52.cpp @@ -700,6 +700,9 @@ static void nRF52_setup() Wire.end(); #if !defined(EXCLUDE_IMU) + pinMode(SOC_GPIO_PIN_T1000_ACC_EN, INPUT_PULLUP); + delay(200); + #if !defined(ARDUINO_ARCH_MBED) Wire.setPins(SOC_GPIO_PIN_T1000_SDA, SOC_GPIO_PIN_T1000_SCL); #endif /* ARDUINO_ARCH_MBED */ @@ -713,6 +716,7 @@ static void nRF52_setup() nRF52_Device_Model = "Card Edition"; } Wire.end(); + pinMode(SOC_GPIO_PIN_T1000_ACC_EN, INPUT); #endif /* EXCLUDE_IMU */ } #endif /* EXCLUDE_PMU */ @@ -750,6 +754,15 @@ static void nRF52_setup() case NRF52_LILYGO_TULTIMA: /* TBD */ break; + + case NRF52_SEEED_T1000: + pinMode(SOC_GPIO_PIN_T1000_3V3_EN, OUTPUT); + digitalWrite(SOC_GPIO_PIN_T1000_3V3_EN, HIGH); + + pinMode(SOC_GPIO_PIN_T1000_BUZZER_EN, OUTPUT); + digitalWrite(SOC_GPIO_PIN_T1000_BUZZER_EN, HIGH); + break; + case NRF52_LILYGO_TECHO_REV_0: case NRF52_LILYGO_TECHO_REV_1: case NRF52_LILYGO_TECHO_REV_2: @@ -896,11 +909,21 @@ static void nRF52_setup() break; case NRF52_SEEED_T1000: - digitalWrite(SOC_GPIO_PIN_GNSS_T1000_RST, LOW); - pinMode(SOC_GPIO_PIN_GNSS_T1000_RST, OUTPUT); digitalWrite(SOC_GPIO_PIN_GNSS_T1000_EN, HIGH); pinMode(SOC_GPIO_PIN_GNSS_T1000_EN, OUTPUT); + pinMode(SOC_GPIO_PIN_GNSS_T1000_VRTC, OUTPUT); + digitalWrite(SOC_GPIO_PIN_GNSS_T1000_VRTC, HIGH); + + digitalWrite(SOC_GPIO_PIN_GNSS_T1000_RST, LOW); + pinMode(SOC_GPIO_PIN_GNSS_T1000_RST, OUTPUT); + + pinMode(SOC_GPIO_PIN_GNSS_T1000_SINT, OUTPUT); + digitalWrite(SOC_GPIO_PIN_GNSS_T1000_SINT, HIGH); + + pinMode(SOC_GPIO_PIN_GNSS_T1000_RINT, OUTPUT); + digitalWrite(SOC_GPIO_PIN_GNSS_T1000_RINT, LOW); + pinMode(SOC_GPIO_LED_T1000_GREEN, OUTPUT); ledOn (SOC_GPIO_LED_T1000_GREEN);