mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-29 19:03:52 +00:00
nimble software update WIP builds
This commit is contained in:
parent
00ca351169
commit
b0e2c81666
@ -3,15 +3,15 @@
|
|||||||
#include "../concurrency/LockGuard.h"
|
#include "../concurrency/LockGuard.h"
|
||||||
#include "../timing.h"
|
#include "../timing.h"
|
||||||
#include "BluetoothSoftwareUpdate.h"
|
#include "BluetoothSoftwareUpdate.h"
|
||||||
|
#include "PowerFSM.h"
|
||||||
#include "RadioLibInterface.h"
|
#include "RadioLibInterface.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "nimble/BluetoothUtil.h"
|
||||||
|
|
||||||
#include <CRC32.h>
|
#include <CRC32.h>
|
||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
|
|
||||||
#include "CallbackCharacteristic.h"
|
int16_t updateResultHandle = -1;
|
||||||
|
|
||||||
int16_t updateResultHandle;
|
|
||||||
|
|
||||||
static CRC32 crc;
|
static CRC32 crc;
|
||||||
static uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
|
static uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
|
||||||
@ -21,20 +21,21 @@ static uint32_t updateExpectedSize, updateActualSize;
|
|||||||
static concurrency::Lock *updateLock;
|
static concurrency::Lock *updateLock;
|
||||||
|
|
||||||
/// Handle writes & reads to total size
|
/// Handle writes & reads to total size
|
||||||
int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||||
{
|
{
|
||||||
concurrency::LockGuard g(updateLock);
|
concurrency::LockGuard g(updateLock);
|
||||||
|
|
||||||
// Check if there is enough to OTA Update
|
// Check if there is enough to OTA Update
|
||||||
uint32_t len = getValue32(c, 0);
|
chr_readwrite32le(&updateExpectedSize, ctxt, arg);
|
||||||
updateExpectedSize = len;
|
|
||||||
|
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR && updateExpectedSize != 0) {
|
||||||
updateActualSize = 0;
|
updateActualSize = 0;
|
||||||
crc.reset();
|
crc.reset();
|
||||||
bool canBegin = Update.begin(len);
|
bool canBegin = Update.begin(updateExpectedSize);
|
||||||
DEBUG_MSG("Setting update size %u, result %d\n", len, canBegin);
|
DEBUG_MSG("Setting update size %u, result %d\n", updateExpectedSize, canBegin);
|
||||||
if (!canBegin) {
|
if (!canBegin) {
|
||||||
// Indicate failure by forcing the size to 0
|
// Indicate failure by forcing the size to 0 (client will read it back)
|
||||||
uint32_t zero = 0;
|
updateExpectedSize = 0;
|
||||||
c->setValue(zero);
|
|
||||||
} else {
|
} else {
|
||||||
// This totally breaks abstraction to up up into the app layer for this, but quick hack to make sure we only
|
// This totally breaks abstraction to up up into the app layer for this, but quick hack to make sure we only
|
||||||
// talk to one service during the sw update.
|
// talk to one service during the sw update.
|
||||||
@ -48,30 +49,42 @@ int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ga
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define MAX_BLOCKSIZE 512
|
#define MAX_BLOCKSIZE 512
|
||||||
|
|
||||||
/// Handle writes to data
|
/// Handle writes to data
|
||||||
int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||||
{
|
{
|
||||||
concurrency::LockGuard g(updateLock);
|
concurrency::LockGuard g(updateLock);
|
||||||
std::string value = c->getValue();
|
|
||||||
uint32_t len = value.length();
|
|
||||||
assert(len <= MAX_BLOCKSIZE);
|
|
||||||
static uint8_t
|
static uint8_t
|
||||||
data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
|
data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
|
||||||
memcpy(data, c->getData(), len);
|
|
||||||
|
uint16_t len = 0;
|
||||||
|
|
||||||
|
auto rc = ble_hs_mbuf_to_flat(ctxt->om, data, sizeof(data), &len);
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
// DEBUG_MSG("Writing %u\n", len);
|
// DEBUG_MSG("Writing %u\n", len);
|
||||||
crc.update(data, len);
|
crc.update(data, len);
|
||||||
Update.write(data, len);
|
Update.write(data, len);
|
||||||
updateActualSize += len;
|
updateActualSize += len;
|
||||||
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG); // Not exactly correct, but we want to force the device to not sleep now
|
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG); // Not exactly correct, but we want to force the device to not sleep now
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t update_result;
|
||||||
|
|
||||||
/// Handle writes to crc32
|
/// Handle writes to crc32
|
||||||
int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||||
{
|
{
|
||||||
concurrency::LockGuard g(updateLock);
|
concurrency::LockGuard g(updateLock);
|
||||||
uint32_t expectedCRC = getValue32(c, 0);
|
uint32_t expectedCRC = 0;
|
||||||
|
chr_readwrite32le(&expectedCRC, ctxt, arg);
|
||||||
|
|
||||||
uint32_t actualCRC = crc.finalize();
|
uint32_t actualCRC = crc.finalize();
|
||||||
DEBUG_MSG("expected CRC %u\n", expectedCRC);
|
DEBUG_MSG("expected CRC %u\n", expectedCRC);
|
||||||
|
|
||||||
@ -97,9 +110,18 @@ int totalSize_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ga
|
|||||||
if (RadioLibInterface::instance)
|
if (RadioLibInterface::instance)
|
||||||
RadioLibInterface::instance->startReceive(); // Resume radio
|
RadioLibInterface::instance->startReceive(); // Resume radio
|
||||||
|
|
||||||
assert(resultC);
|
assert(updateResultHandle >= 0);
|
||||||
resultC->setValue(&result, 1);
|
update_result = result;
|
||||||
resultC->notify();
|
DEBUG_MSG("BLE notify update result\n");
|
||||||
|
auto res = ble_gattc_notify(curConnectionHandle, updateResultHandle);
|
||||||
|
assert(res == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||||
|
{
|
||||||
|
return chr_readwrite8(&update_result, sizeof(update_result), ctxt, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bluetoothRebootCheck()
|
void bluetoothRebootCheck()
|
||||||
|
@ -365,6 +365,10 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
|||||||
fromNumValHandle = ctxt->chr.val_handle;
|
fromNumValHandle = ctxt->chr.val_handle;
|
||||||
DEBUG_MSG("FromNum handle %d\n", fromNumValHandle);
|
DEBUG_MSG("FromNum handle %d\n", fromNumValHandle);
|
||||||
}
|
}
|
||||||
|
if (ctxt->chr.chr_def->uuid == &update_result_uuid.u) {
|
||||||
|
updateResultHandle = ctxt->chr.val_handle;
|
||||||
|
DEBUG_MSG("update result handle %d\n", updateResultHandle);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLE_GATT_REGISTER_OP_DSC:
|
case BLE_GATT_REGISTER_OP_DSC:
|
||||||
@ -377,6 +381,68 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper function that implements simple read and write handling for a uint32_t
|
||||||
|
*
|
||||||
|
* If a read, the provided value will be returned over bluetooth. If a write, the value from the received packet
|
||||||
|
* will be written into the variable.
|
||||||
|
*/
|
||||||
|
int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||||
|
{
|
||||||
|
uint8_t le[4];
|
||||||
|
|
||||||
|
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||||
|
DEBUG_MSG("BLE reading a uint32\n");
|
||||||
|
put_le32(le, *v);
|
||||||
|
auto rc = os_mbuf_append(ctxt->om, le, sizeof(le));
|
||||||
|
assert(rc == 0);
|
||||||
|
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||||
|
uint16_t len = 0;
|
||||||
|
|
||||||
|
auto rc = ble_hs_mbuf_to_flat(ctxt->om, le, sizeof(le), &len);
|
||||||
|
assert(rc == 0);
|
||||||
|
if (len < sizeof(le)) {
|
||||||
|
DEBUG_MSG("Error: wrongsized write32\n");
|
||||||
|
*v = 0;
|
||||||
|
} else {
|
||||||
|
*v = get_le32(le);
|
||||||
|
DEBUG_MSG("BLE writing a uint32\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Unexpected readwrite32 op\n");
|
||||||
|
return BLE_ATT_ERR_UNLIKELY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // success
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper for readwrite access to an array of bytes (with no endian conversion)
|
||||||
|
*/
|
||||||
|
int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||||
|
{
|
||||||
|
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||||
|
DEBUG_MSG("BLE reading bytes\n");
|
||||||
|
auto rc = os_mbuf_append(ctxt->om, v, vlen);
|
||||||
|
assert(rc == 0);
|
||||||
|
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||||
|
uint16_t len = 0;
|
||||||
|
|
||||||
|
auto rc = ble_hs_mbuf_to_flat(ctxt->om, v, vlen, &len);
|
||||||
|
assert(rc == 0);
|
||||||
|
if (len < vlen)
|
||||||
|
DEBUG_MSG("Error: wrongsized write\n");
|
||||||
|
else {
|
||||||
|
DEBUG_MSG("BLE writing bytes\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Unexpected readwrite8 op\n");
|
||||||
|
return BLE_ATT_ERR_UNLIKELY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // success
|
||||||
|
}
|
||||||
|
|
||||||
// This routine is called multiple times, once each time we come back from sleep
|
// This routine is called multiple times, once each time we come back from sleep
|
||||||
void reinitBluetooth()
|
void reinitBluetooth()
|
||||||
{
|
{
|
||||||
|
@ -1,36 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "SimpleAllocator.h"
|
/// We only allow one BLE connection at a time
|
||||||
#include <Arduino.h>
|
extern int16_t curConnectionHandle;
|
||||||
#include <BLEDevice.h>
|
|
||||||
#include <BLEServer.h>
|
|
||||||
#include <BLEUtils.h>
|
|
||||||
|
|
||||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
|
||||||
|
|
||||||
// Help routine to add a description to any BLECharacteristic and add it to the service
|
|
||||||
void addWithDesc(BLEService *service, BLECharacteristic *c, const char *description);
|
|
||||||
|
|
||||||
void dumpCharacteristic(BLECharacteristic *c);
|
|
||||||
|
|
||||||
/** converting endianness pull out a 32 bit value */
|
|
||||||
uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue);
|
|
||||||
|
|
||||||
BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen,
|
|
||||||
std::string devName, std::string hwVendor, std::string swVersion, std::string hwVersion = "");
|
|
||||||
|
|
||||||
/// Add a characteristic that we will delete when we restart
|
|
||||||
BLECharacteristic *addBLECharacteristic(BLECharacteristic *c);
|
|
||||||
|
|
||||||
/// Add a characteristic that we will delete when we restart
|
|
||||||
BLEDescriptor *addBLEDescriptor(BLEDescriptor *c);
|
|
||||||
|
|
||||||
/// Any bluetooth objects you allocate _must_ come from this pool if you want to be able to call deinitBLE()
|
|
||||||
extern SimpleAllocator btPool;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO(girts): create a class for the bluetooth utils helpers?
|
// TODO(girts): create a class for the bluetooth utils helpers?
|
||||||
using StartBluetoothPinScreenCallback = std::function<void(uint32_t pass_key)>;
|
using StartBluetoothPinScreenCallback = std::function<void(uint32_t pass_key)>;
|
||||||
@ -41,3 +15,16 @@ void updateBatteryLevel(uint8_t level);
|
|||||||
void deinitBLE();
|
void deinitBLE();
|
||||||
void loopBLE();
|
void loopBLE();
|
||||||
void reinitBluetooth();
|
void reinitBluetooth();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper function that implements simple read and write handling for a uint32_t
|
||||||
|
*
|
||||||
|
* If a read, the provided value will be returned over bluetooth. If a write, the value from the received packet
|
||||||
|
* will be written into the variable.
|
||||||
|
*/
|
||||||
|
int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper for readwrite access to an array of bytes (with no endian conversion)
|
||||||
|
*/
|
||||||
|
int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
@ -1,11 +1,13 @@
|
|||||||
#include "NimbleBluetoothAPI.h"
|
#include "NimbleBluetoothAPI.h"
|
||||||
#include "PhoneAPI.h"
|
#include "PhoneAPI.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "nimble/BluetoothUtil.h"
|
||||||
#include "nimble/NimbleDefs.h"
|
#include "nimble/NimbleDefs.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
|
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
|
||||||
// proccess at once
|
// proccess at once
|
||||||
static uint8_t trBytes[max(FromRadio_size, ToRadio_size)];
|
static uint8_t trBytes[FromRadio_size < ToRadio_size ? ToRadio_size : FromRadio_size];
|
||||||
static uint32_t fromNum;
|
static uint32_t fromNum;
|
||||||
|
|
||||||
uint16_t fromNumValHandle;
|
uint16_t fromNumValHandle;
|
||||||
@ -60,10 +62,5 @@ int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ga
|
|||||||
|
|
||||||
int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||||
{
|
{
|
||||||
// DEBUG_MSG("BLE fromNum called\n");
|
return chr_readwrite32le(&fromNum, ctxt, arg);
|
||||||
auto rc = os_mbuf_append(ctxt->om, &fromNum,
|
|
||||||
sizeof(fromNum)); // FIXME - once we report real numbers we will need to consider endianness
|
|
||||||
assert(rc == 0);
|
|
||||||
|
|
||||||
return 0; // success
|
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,6 @@
|
|||||||
|
|
||||||
extern uint16_t fromNumValHandle;
|
extern uint16_t fromNumValHandle;
|
||||||
|
|
||||||
/// We only allow one BLE connection at a time
|
|
||||||
extern int16_t curConnectionHandle;
|
|
||||||
|
|
||||||
class BluetoothPhoneAPI : public PhoneAPI
|
class BluetoothPhoneAPI : public PhoneAPI
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// Keep nimble #defs from messing up the build
|
||||||
|
#ifndef max
|
||||||
|
#define max max
|
||||||
|
#define min min
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "esp_nimble_hci.h"
|
#include "esp_nimble_hci.h"
|
||||||
#include "host/ble_hs.h"
|
#include "host/ble_hs.h"
|
||||||
#include "host/ble_uuid.h"
|
#include "host/ble_uuid.h"
|
||||||
#include "nimble/nimble_port.h"
|
#include "nimble/nimble_port.h"
|
||||||
#include "nimble/nimble_port_freertos.h"
|
#include "nimble/nimble_port_freertos.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
Loading…
Reference in New Issue
Block a user