Fix formatting

This commit is contained in:
beegee-tokyo 2024-09-12 11:06:13 +08:00
parent a388e78842
commit ca8d2204ba
4 changed files with 1194 additions and 1014 deletions

View File

@ -96,7 +96,7 @@ class AccelerometerThread : public concurrency::OSThread
} }
#if defined(RAK_4631) #if defined(RAK_4631)
#if !defined (MESHTASTIC_EXCLUDE_SCREEN) #if !defined (MESHTASTIC_EXCLUDE_SCREEN)
} else if (acceleremoter_type == ScanI2C::DeviceType::BMX160) { } else if (acceleremoter_type == ScanI2C::DeviceType::BMX160) {
sBmx160SensorData_t magAccel; sBmx160SensorData_t magAccel;
sBmx160SensorData_t gAccel; sBmx160SensorData_t gAccel;
@ -232,7 +232,7 @@ class AccelerometerThread : public concurrency::OSThread
bmaSensor.enableWakeupIRQ(); bmaSensor.enableWakeupIRQ();
#ifdef RAK_4631 #ifdef RAK_4631
#if !defined(MESHTASTIC_EXCLUDE_SCREEN) #if !defined(MESHTASTIC_EXCLUDE_SCREEN)
} else if (acceleremoter_type == ScanI2C::DeviceType::BMX160 && bmx160.begin()) { } else if (acceleremoter_type == ScanI2C::DeviceType::BMX160 && bmx160.begin()) {
bmx160.ODR_Config(BMX160_ACCEL_ODR_100HZ, BMX160_GYRO_ODR_100HZ); // set output data rate bmx160.ODR_Config(BMX160_ACCEL_ODR_100HZ, BMX160_GYRO_ODR_100HZ); // set output data rate
#endif #endif
#endif #endif
@ -268,7 +268,7 @@ class AccelerometerThread : public concurrency::OSThread
SensorBMA423 bmaSensor; SensorBMA423 bmaSensor;
bool BMA_IRQ = false; bool BMA_IRQ = false;
#if defined(RAK_4631) && !defined(MESHTASTIC_EXCLUDE_SCREEN) #if defined(RAK_4631) && !defined(MESHTASTIC_EXCLUDE_SCREEN)
bool showingScreen = false; bool showingScreen = false;
RAK_BMX160 bmx160; RAK_BMX160 bmx160;
float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0; float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0;

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ static BLEBas blebas; // BAS (Battery Service) helper class instance
#ifndef BLE_DFU_SECURE #ifndef BLE_DFU_SECURE
static BLEDfu bledfu; // DFU software update helper service static BLEDfu bledfu; // DFU software update helper service
#else #else
static BLEDfuSecure bledfusecure; // DFU software update helper service static BLEDfuSecure bledfusecure; // DFU software update helper service
#endif #endif
// 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
@ -32,23 +32,23 @@ static uint16_t connectionHandle;
class BluetoothPhoneAPI : public PhoneAPI class BluetoothPhoneAPI : public PhoneAPI
{ {
/** /**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies) * Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/ */
virtual void onNowHasData(uint32_t fromRadioNum) override virtual void onNowHasData(uint32_t fromRadioNum) override
{ {
PhoneAPI::onNowHasData(fromRadioNum); PhoneAPI::onNowHasData(fromRadioNum);
LOG_INFO("BLE notify fromNum\n"); LOG_INFO("BLE notify fromNum\n");
fromNum.notify32(fromRadioNum); fromNum.notify32(fromRadioNum);
} }
/// Check the current underlying physical link to see if the client is currently connected /// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override virtual bool checkIsConnected() override
{ {
BLEConnection *connection = Bluefruit.Connection(connectionHandle); BLEConnection *connection = Bluefruit.Connection(connectionHandle);
return connection->connected(); return connection->connected();
} }
}; };
static BluetoothPhoneAPI *bluetoothPhoneAPI; static BluetoothPhoneAPI *bluetoothPhoneAPI;
@ -56,12 +56,12 @@ static BluetoothPhoneAPI *bluetoothPhoneAPI;
void onConnect(uint16_t conn_handle) void onConnect(uint16_t conn_handle)
{ {
// Get the reference to current connection // Get the reference to current connection
BLEConnection *connection = Bluefruit.Connection(conn_handle); BLEConnection *connection = Bluefruit.Connection(conn_handle);
connectionHandle = conn_handle; connectionHandle = conn_handle;
char central_name[32] = {0}; char central_name[32] = {0};
connection->getPeerName(central_name, sizeof(central_name)); connection->getPeerName(central_name, sizeof(central_name));
LOG_INFO("BLE Connected to %s\n", central_name); LOG_INFO("BLE Connected to %s\n", central_name);
} }
/** /**
* Callback invoked when a connection is dropped * Callback invoked when a connection is dropped
@ -70,246 +70,258 @@ void onConnect(uint16_t conn_handle)
*/ */
void onDisconnect(uint16_t conn_handle, uint8_t reason) void onDisconnect(uint16_t conn_handle, uint8_t reason)
{ {
// FIXME - we currently assume only one active connection // FIXME - we currently assume only one active connection
LOG_INFO("BLE Disconnected, reason = 0x%x\n", reason); LOG_INFO("BLE Disconnected, reason = 0x%x\n", reason);
} }
void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value) void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
{ {
// Display the raw request packet // Display the raw request packet
LOG_INFO("CCCD Updated: %u\n", cccd_value); LOG_INFO("CCCD Updated: %u\n", cccd_value);
// Check the characteristic this CCCD update is associated with in case // Check the characteristic this CCCD update is associated with in case
// this handler is used for multiple CCCD records. // this handler is used for multiple CCCD records.
// According to the GATT spec: cccd value = 0x0001 means notifications are enabled // According to the GATT spec: cccd value = 0x0001 means notifications are enabled
// and cccd value = 0x0002 means indications are enabled // and cccd value = 0x0002 means indications are enabled
if (chr->uuid == fromNum.uuid || chr->uuid == logRadio.uuid) { if (chr->uuid == fromNum.uuid || chr->uuid == logRadio.uuid)
auto result = cccd_value == 2 ? chr->indicateEnabled(conn_hdl) : chr->notifyEnabled(conn_hdl); {
if (result) { auto result = cccd_value == 2 ? chr->indicateEnabled(conn_hdl) : chr->notifyEnabled(conn_hdl);
LOG_INFO("Notify/Indicate enabled\n"); if (result)
} else { {
LOG_INFO("Notify/Indicate disabled\n"); LOG_INFO("Notify/Indicate enabled\n");
} }
} else
{
LOG_INFO("Notify/Indicate disabled\n");
}
}
} }
void startAdv(void) void startAdv(void)
{ {
// Advertising packet // Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
// IncludeService UUID // IncludeService UUID
// Bluefruit.ScanResponse.addService(meshBleService); // Bluefruit.ScanResponse.addService(meshBleService);
Bluefruit.ScanResponse.addTxPower(); Bluefruit.ScanResponse.addTxPower();
Bluefruit.ScanResponse.addName(); Bluefruit.ScanResponse.addName();
// Include Name // Include Name
// Bluefruit.Advertising.addName(); // Bluefruit.Advertising.addName();
Bluefruit.Advertising.addService(meshBleService); Bluefruit.Advertising.addService(meshBleService);
/* Start Advertising /* Start Advertising
* - Enable auto advertising if disconnected * - Enable auto advertising if disconnected
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
* - Timeout for fast mode is 30 seconds * - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected) * - Start(timeout) with timeout = 0 will advertise forever (until connected)
* *
* For recommended advertising interval * For recommended advertising interval
* https://developer.apple.com/library/content/qa/qa1931/_index.html * https://developer.apple.com/library/content/qa/qa1931/_index.html
*/ */
Bluefruit.Advertising.restartOnDisconnect(true); Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X
} }
// Just ack that the caller is allowed to read // Just ack that the caller is allowed to read
static void authorizeRead(uint16_t conn_hdl) static void authorizeRead(uint16_t conn_hdl)
{ {
ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_READ}; ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_READ};
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
} }
/** /**
* client is starting read, pull the bytes from our API class * client is starting read, pull the bytes from our API class
*/ */
void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
{ {
if (request->offset == 0) { if (request->offset == 0)
// If the read is long, we will get multiple authorize invocations - we only populate data on the first {
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); // If the read is long, we will get multiple authorize invocations - we only populate data on the first
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
// or make empty if the queue is empty // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
fromRadio.write(fromRadioBytes, numBytes); // or make empty if the queue is empty
} else { fromRadio.write(fromRadioBytes, numBytes);
// LOG_INFO("Ignoring successor read\n"); }
} else
authorizeRead(conn_hdl); {
// LOG_INFO("Ignoring successor read\n");
}
authorizeRead(conn_hdl);
} }
void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len) void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
{ {
LOG_INFO("toRadioWriteCb data %p, len %u\n", data, len); LOG_INFO("toRadioWriteCb data %p, len %u\n", data, len);
bluetoothPhoneAPI->handleToRadio(data, len); bluetoothPhoneAPI->handleToRadio(data, len);
} }
void setupMeshService(void) void setupMeshService(void)
{ {
bluetoothPhoneAPI = new BluetoothPhoneAPI(); bluetoothPhoneAPI = new BluetoothPhoneAPI();
meshBleService.begin(); meshBleService.begin();
// Note: You must call .begin() on the BLEService before calling .begin() on // Note: You must call .begin() on the BLEService before calling .begin() on
// any characteristic(s) within that service definition.. Calling .begin() on // any characteristic(s) within that service definition.. Calling .begin() on
// a BLECharacteristic will cause it to be added to the last BLEService that // a BLECharacteristic will cause it to be added to the last BLEService that
// was 'begin()'ed! // was 'begin()'ed!
auto secMode = auto secMode =
config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN ? SECMODE_OPEN : SECMODE_ENC_NO_MITM; config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN ? SECMODE_OPEN : SECMODE_ENC_NO_MITM;
fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ); fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ);
fromNum.setPermission(secMode, SECMODE_NO_ACCESS); // FIXME, secure this!!! fromNum.setPermission(secMode, SECMODE_NO_ACCESS); // FIXME, secure this!!!
fromNum.setFixedLen( fromNum.setFixedLen(
0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty 0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty
fromNum.setMaxLen(4); fromNum.setMaxLen(4);
fromNum.setCccdWriteCallback(onCccd); // Optionally capture CCCD updates fromNum.setCccdWriteCallback(onCccd); // Optionally capture CCCD updates
// We don't yet need to hook the fromNum auth callback // We don't yet need to hook the fromNum auth callback
// fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb); // fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb);
fromNum.write32(0); // Provide default fromNum of 0 fromNum.write32(0); // Provide default fromNum of 0
fromNum.begin(); fromNum.begin();
fromRadio.setProperties(CHR_PROPS_READ); fromRadio.setProperties(CHR_PROPS_READ);
fromRadio.setPermission(secMode, SECMODE_NO_ACCESS); fromRadio.setPermission(secMode, SECMODE_NO_ACCESS);
fromRadio.setMaxLen(sizeof(fromRadioBytes)); fromRadio.setMaxLen(sizeof(fromRadioBytes));
fromRadio.setReadAuthorizeCallback( fromRadio.setReadAuthorizeCallback(
onFromRadioAuthorize, onFromRadioAuthorize,
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space
// for two copies // for two copies
fromRadio.begin(); fromRadio.begin();
toRadio.setProperties(CHR_PROPS_WRITE); toRadio.setProperties(CHR_PROPS_WRITE);
toRadio.setPermission(secMode, secMode); // FIXME secure this! toRadio.setPermission(secMode, secMode); // FIXME secure this!
toRadio.setFixedLen(0); toRadio.setFixedLen(0);
toRadio.setMaxLen(512); toRadio.setMaxLen(512);
toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes)); toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes));
// We don't call this callback via the adafruit queue, because we can safely run in the BLE context // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
toRadio.setWriteCallback(onToRadioWrite, false); toRadio.setWriteCallback(onToRadioWrite, false);
toRadio.begin(); toRadio.begin();
logRadio.setProperties(CHR_PROPS_INDICATE | CHR_PROPS_NOTIFY | CHR_PROPS_READ); logRadio.setProperties(CHR_PROPS_INDICATE | CHR_PROPS_NOTIFY | CHR_PROPS_READ);
logRadio.setPermission(secMode, SECMODE_NO_ACCESS); logRadio.setPermission(secMode, SECMODE_NO_ACCESS);
logRadio.setMaxLen(512); logRadio.setMaxLen(512);
logRadio.setCccdWriteCallback(onCccd); logRadio.setCccdWriteCallback(onCccd);
logRadio.write32(0); logRadio.write32(0);
logRadio.begin(); logRadio.begin();
} }
static uint32_t configuredPasskey; static uint32_t configuredPasskey;
void NRF52Bluetooth::shutdown() void NRF52Bluetooth::shutdown()
{ {
// Shutdown bluetooth for minimum power draw // Shutdown bluetooth for minimum power draw
LOG_INFO("Disable NRF52 bluetooth\n"); LOG_INFO("Disable NRF52 bluetooth\n");
uint8_t connection_num = Bluefruit.connected(); uint8_t connection_num = Bluefruit.connected();
if (connection_num) { if (connection_num)
for (uint8_t i = 0; i < connection_num; i++) { {
LOG_INFO("NRF52 bluetooth disconnecting handle %d\n", i); for (uint8_t i = 0; i < connection_num; i++)
Bluefruit.disconnect(i); {
} LOG_INFO("NRF52 bluetooth disconnecting handle %d\n", i);
delay(100); // wait for ondisconnect; Bluefruit.disconnect(i);
} }
Bluefruit.Advertising.stop(); delay(100); // wait for ondisconnect;
}
Bluefruit.Advertising.stop();
} }
void NRF52Bluetooth::startDisabled() void NRF52Bluetooth::startDisabled()
{ {
// Setup Bluetooth // Setup Bluetooth
nrf52Bluetooth->setup(); nrf52Bluetooth->setup();
// Shutdown bluetooth for minimum power draw // Shutdown bluetooth for minimum power draw
Bluefruit.Advertising.stop(); Bluefruit.Advertising.stop();
Bluefruit.setTxPower(-40); // Minimum power Bluefruit.setTxPower(-40); // Minimum power
LOG_INFO("Disabling NRF52 Bluetooth. (Workaround: tx power min, advertising stopped)\n"); LOG_INFO("Disabling NRF52 Bluetooth. (Workaround: tx power min, advertising stopped)\n");
} }
bool NRF52Bluetooth::isConnected() bool NRF52Bluetooth::isConnected()
{ {
return Bluefruit.connected(connectionHandle); return Bluefruit.connected(connectionHandle);
} }
int NRF52Bluetooth::getRssi() int NRF52Bluetooth::getRssi()
{ {
return 0; // FIXME figure out where to source this return 0; // FIXME figure out where to source this
} }
void NRF52Bluetooth::setup() void NRF52Bluetooth::setup()
{ {
// Initialise the Bluefruit module // Initialise the Bluefruit module
LOG_INFO("Initialize the Bluefruit nRF52 module\n"); LOG_INFO("Initialize the Bluefruit nRF52 module\n");
Bluefruit.autoConnLed(false); Bluefruit.autoConnLed(false);
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.begin(); Bluefruit.begin();
// Clear existing data. // Clear existing data.
Bluefruit.Advertising.stop(); Bluefruit.Advertising.stop();
Bluefruit.Advertising.clearData(); Bluefruit.Advertising.clearData();
Bluefruit.ScanResponse.clearData(); Bluefruit.ScanResponse.clearData();
if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) { if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN)
configuredPasskey = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN {
? config.bluetooth.fixed_pin configuredPasskey = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN
: random(100000, 999999); ? config.bluetooth.fixed_pin
auto pinString = std::to_string(configuredPasskey); : random(100000, 999999);
LOG_INFO("Bluetooth pin set to '%i'\n", configuredPasskey); auto pinString = std::to_string(configuredPasskey);
Bluefruit.Security.setPIN(pinString.c_str()); LOG_INFO("Bluetooth pin set to '%i'\n", configuredPasskey);
Bluefruit.Security.setIOCaps(true, false, false); Bluefruit.Security.setPIN(pinString.c_str());
Bluefruit.Security.setPairPasskeyCallback(NRF52Bluetooth::onPairingPasskey); Bluefruit.Security.setIOCaps(true, false, false);
Bluefruit.Security.setPairCompleteCallback(NRF52Bluetooth::onPairingCompleted); Bluefruit.Security.setPairPasskeyCallback(NRF52Bluetooth::onPairingPasskey);
Bluefruit.Security.setSecuredCallback(NRF52Bluetooth::onConnectionSecured); Bluefruit.Security.setPairCompleteCallback(NRF52Bluetooth::onPairingCompleted);
meshBleService.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); Bluefruit.Security.setSecuredCallback(NRF52Bluetooth::onConnectionSecured);
} else { meshBleService.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
Bluefruit.Security.setIOCaps(false, false, false); }
meshBleService.setPermission(SECMODE_OPEN, SECMODE_OPEN); else
} {
// Set the advertised device name (keep it short!) Bluefruit.Security.setIOCaps(false, false, false);
Bluefruit.setName(getDeviceName()); meshBleService.setPermission(SECMODE_OPEN, SECMODE_OPEN);
// Set the connect/disconnect callback handlers }
Bluefruit.Periph.setConnectCallback(onConnect); // Set the advertised device name (keep it short!)
Bluefruit.Periph.setDisconnectCallback(onDisconnect); Bluefruit.setName(getDeviceName());
// Set the connect/disconnect callback handlers
Bluefruit.Periph.setConnectCallback(onConnect);
Bluefruit.Periph.setDisconnectCallback(onDisconnect);
#ifndef BLE_DFU_SECURE #ifndef BLE_DFU_SECURE
bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
bledfu.begin(); // Install the DFU helper bledfu.begin(); // Install the DFU helper
#else #else
bledfusecure.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // add by WayenWeng bledfusecure.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // add by WayenWeng
bledfusecure.begin(); // Install the DFU helper bledfusecure.begin(); // Install the DFU helper
#endif #endif
// Configure and Start the Device Information Service // Configure and Start the Device Information Service
LOG_INFO("Configuring the Device Information Service\n"); LOG_INFO("Configuring the Device Information Service\n");
bledis.setModel(optstr(HW_VERSION)); bledis.setModel(optstr(HW_VERSION));
bledis.setFirmwareRev(optstr(APP_VERSION)); bledis.setFirmwareRev(optstr(APP_VERSION));
bledis.begin(); bledis.begin();
// Start the BLE Battery Service and set it to 100% // Start the BLE Battery Service and set it to 100%
LOG_INFO("Configuring the Battery Service\n"); LOG_INFO("Configuring the Battery Service\n");
blebas.begin(); blebas.begin();
blebas.write(0); // Unknown battery level for now blebas.write(0); // Unknown battery level for now
// Setup the Heart Rate Monitor service using // Setup the Heart Rate Monitor service using
// BLEService and BLECharacteristic classes // BLEService and BLECharacteristic classes
LOG_INFO("Configuring the Mesh bluetooth service\n"); LOG_INFO("Configuring the Mesh bluetooth service\n");
setupMeshService(); setupMeshService();
// Setup the advertising packet(s) // Setup the advertising packet(s)
LOG_INFO("Setting up the advertising payload(s)\n"); LOG_INFO("Setting up the advertising payload(s)\n");
startAdv(); startAdv();
LOG_INFO("Advertising\n"); LOG_INFO("Advertising\n");
} }
void NRF52Bluetooth::resumeAdvertising() void NRF52Bluetooth::resumeAdvertising()
{ {
Bluefruit.Advertising.restartOnDisconnect(true); Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); Bluefruit.Advertising.start(0);
} }
/// Given a level between 0-100, update the BLE attribute /// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level) void updateBatteryLevel(uint8_t level)
{ {
blebas.write(level); blebas.write(level);
} }
void NRF52Bluetooth::clearBonds() void NRF52Bluetooth::clearBonds()
{ {
LOG_INFO("Clearing bluetooth bonds!\n"); LOG_INFO("Clearing bluetooth bonds!\n");
bond_print_list(BLE_GAP_ROLE_PERIPH); bond_print_list(BLE_GAP_ROLE_PERIPH);
bond_print_list(BLE_GAP_ROLE_CENTRAL); bond_print_list(BLE_GAP_ROLE_CENTRAL);
Bluefruit.Periph.clearBonds(); Bluefruit.Periph.clearBonds();
Bluefruit.Central.clearBonds(); Bluefruit.Central.clearBonds();
} }
void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle) void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle)
{ {
LOG_INFO("BLE connection secured\n"); LOG_INFO("BLE connection secured\n");
} }
bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request)
{ {
LOG_INFO("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey + 3); LOG_INFO("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey + 3);
powerFSM.trigger(EVENT_BLUETOOTH_PAIR); powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
#if !defined(MESHTASTIC_EXCLUDE_SCREEN) #if !defined(MESHTASTIC_EXCLUDE_SCREEN)
screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void
{ {
@ -337,31 +349,33 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke
y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5;
display->drawString(x_offset + x, y_offset + y, deviceName); }); display->drawString(x_offset + x, y_offset + y, deviceName); });
#endif #endif
if (match_request) { if (match_request)
uint32_t start_time = millis(); {
while (millis() < start_time + 30000) { uint32_t start_time = millis();
if (!Bluefruit.connected(conn_handle)) while (millis() < start_time + 30000)
break; {
} if (!Bluefruit.connected(conn_handle))
} break;
LOG_INFO("BLE passkey pairing: match_request=%i\n", match_request); }
return true; }
LOG_INFO("BLE passkey pairing: match_request=%i\n", match_request);
return true;
} }
void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status) void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status)
{ {
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
LOG_INFO("BLE pairing success\n"); LOG_INFO("BLE pairing success\n");
else else
LOG_INFO("BLE pairing failed\n"); LOG_INFO("BLE pairing failed\n");
screen->endAlert(); screen->endAlert();
} }
void NRF52Bluetooth::sendLog(const uint8_t *logMessage, size_t length) void NRF52Bluetooth::sendLog(const uint8_t *logMessage, size_t length)
{ {
if (!isConnected() || length > 512) if (!isConnected() || length > 512)
return; return;
if (logRadio.indicateEnabled()) if (logRadio.indicateEnabled())
logRadio.indicate(logMessage, (uint16_t)length); logRadio.indicate(logMessage, (uint16_t)length);
else else
logRadio.notify(logMessage, (uint16_t)length); logRadio.notify(logMessage, (uint16_t)length);
} }

View File

@ -16,296 +16,360 @@ StaticJsonDocument<1024> arrayObj;
std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog) std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog)
{ {
// the created jsonObj is immutable after creation, so // the created jsonObj is immutable after creation, so
// we need to do the heavy lifting before assembling it. // we need to do the heavy lifting before assembling it.
std::string msgType; std::string msgType;
jsonObj.clear(); jsonObj.clear();
arrayObj.clear(); arrayObj.clear();
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag)
switch (mp->decoded.portnum) { {
case meshtastic_PortNum_TEXT_MESSAGE_APP: { switch (mp->decoded.portnum)
msgType = "text"; {
// convert bytes to string case meshtastic_PortNum_TEXT_MESSAGE_APP:
if (shouldLog) {
LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size); msgType = "text";
// convert bytes to string
if (shouldLog)
LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size);
char payloadStr[(mp->decoded.payload.size) + 1]; char payloadStr[(mp->decoded.payload.size) + 1];
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size); memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
payloadStr[mp->decoded.payload.size] = 0; // null terminated string payloadStr[mp->decoded.payload.size] = 0; // null terminated string
// check if this is a JSON payload // check if this is a JSON payload
StaticJsonDocument<512> text_doc; StaticJsonDocument<512> text_doc;
DeserializationError error = deserializeJson(text_doc, payloadStr); DeserializationError error = deserializeJson(text_doc, payloadStr);
if (error) { if (error)
{
// if it isn't, then we need to create a json object // if it isn't, then we need to create a json object
// with the string as the value // with the string as the value
if (shouldLog) if (shouldLog)
LOG_INFO("text message payload is of type plaintext\n"); LOG_INFO("text message payload is of type plaintext\n");
jsonObj["payload"]["text"] = payloadStr; jsonObj["payload"]["text"] = payloadStr;
} else { }
else
{
// if it is, then we can just use the json object // if it is, then we can just use the json object
if (shouldLog) if (shouldLog)
LOG_INFO("text message payload is of type json\n"); LOG_INFO("text message payload is of type json\n");
jsonObj["payload"] = text_doc; jsonObj["payload"] = text_doc;
} }
break; break;
} }
case meshtastic_PortNum_TELEMETRY_APP: { case meshtastic_PortNum_TELEMETRY_APP:
msgType = "telemetry"; {
meshtastic_Telemetry scratch; msgType = "telemetry";
meshtastic_Telemetry *decoded = NULL; meshtastic_Telemetry scratch;
memset(&scratch, 0, sizeof(scratch)); meshtastic_Telemetry *decoded = NULL;
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) { memset(&scratch, 0, sizeof(scratch));
decoded = &scratch; if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch))
if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) { {
jsonObj["payload"]["battery_level"] = (unsigned int)decoded->variant.device_metrics.battery_level; decoded = &scratch;
jsonObj["payload"]["voltage"] = decoded->variant.device_metrics.voltage; if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag)
jsonObj["payload"]["channel_utilization"] = decoded->variant.device_metrics.channel_utilization; {
jsonObj["payload"]["air_util_tx"] = decoded->variant.device_metrics.air_util_tx; jsonObj["payload"]["battery_level"] = (unsigned int)decoded->variant.device_metrics.battery_level;
jsonObj["payload"]["uptime_seconds"] = (unsigned int)decoded->variant.device_metrics.uptime_seconds; jsonObj["payload"]["voltage"] = decoded->variant.device_metrics.voltage;
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) { jsonObj["payload"]["channel_utilization"] = decoded->variant.device_metrics.channel_utilization;
jsonObj["payload"]["temperature"] = decoded->variant.environment_metrics.temperature; jsonObj["payload"]["air_util_tx"] = decoded->variant.device_metrics.air_util_tx;
jsonObj["payload"]["relative_humidity"] = decoded->variant.environment_metrics.relative_humidity; jsonObj["payload"]["uptime_seconds"] = (unsigned int)decoded->variant.device_metrics.uptime_seconds;
jsonObj["payload"]["barometric_pressure"] = decoded->variant.environment_metrics.barometric_pressure; }
jsonObj["payload"]["gas_resistance"] = decoded->variant.environment_metrics.gas_resistance; else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag)
jsonObj["payload"]["voltage"] = decoded->variant.environment_metrics.voltage; {
jsonObj["payload"]["current"] = decoded->variant.environment_metrics.current; jsonObj["payload"]["temperature"] = decoded->variant.environment_metrics.temperature;
jsonObj["payload"]["lux"] = decoded->variant.environment_metrics.lux; jsonObj["payload"]["relative_humidity"] = decoded->variant.environment_metrics.relative_humidity;
jsonObj["payload"]["white_lux"] = decoded->variant.environment_metrics.white_lux; jsonObj["payload"]["barometric_pressure"] = decoded->variant.environment_metrics.barometric_pressure;
jsonObj["payload"]["iaq"] = (uint)decoded->variant.environment_metrics.iaq; jsonObj["payload"]["gas_resistance"] = decoded->variant.environment_metrics.gas_resistance;
jsonObj["payload"]["wind_speed"] = decoded->variant.environment_metrics.wind_speed; jsonObj["payload"]["voltage"] = decoded->variant.environment_metrics.voltage;
jsonObj["payload"]["wind_direction"] = (uint)decoded->variant.environment_metrics.wind_direction; jsonObj["payload"]["current"] = decoded->variant.environment_metrics.current;
jsonObj["payload"]["wind_gust"] = decoded->variant.environment_metrics.wind_gust; jsonObj["payload"]["lux"] = decoded->variant.environment_metrics.lux;
jsonObj["payload"]["wind_lull"] = decoded->variant.environment_metrics.wind_lull; jsonObj["payload"]["white_lux"] = decoded->variant.environment_metrics.white_lux;
} else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) { jsonObj["payload"]["iaq"] = (uint)decoded->variant.environment_metrics.iaq;
jsonObj["payload"]["pm10"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_standard; jsonObj["payload"]["wind_speed"] = decoded->variant.environment_metrics.wind_speed;
jsonObj["payload"]["pm25"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_standard; jsonObj["payload"]["wind_direction"] = (uint)decoded->variant.environment_metrics.wind_direction;
jsonObj["payload"]["pm100"] = (unsigned int)decoded->variant.air_quality_metrics.pm100_standard; jsonObj["payload"]["wind_gust"] = decoded->variant.environment_metrics.wind_gust;
jsonObj["payload"]["pm10_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_environmental; jsonObj["payload"]["wind_lull"] = decoded->variant.environment_metrics.wind_lull;
jsonObj["payload"]["pm25_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_environmental; }
jsonObj["payload"]["pm100_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm100_environmental; else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag)
} else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) { {
jsonObj["payload"]["voltage_ch1"] = decoded->variant.power_metrics.ch1_voltage; jsonObj["payload"]["pm10"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_standard;
jsonObj["payload"]["current_ch1"] = decoded->variant.power_metrics.ch1_current; jsonObj["payload"]["pm25"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_standard;
jsonObj["payload"]["voltage_ch2"] = decoded->variant.power_metrics.ch2_voltage; jsonObj["payload"]["pm100"] = (unsigned int)decoded->variant.air_quality_metrics.pm100_standard;
jsonObj["payload"]["current_ch2"] = decoded->variant.power_metrics.ch2_current; jsonObj["payload"]["pm10_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_environmental;
jsonObj["payload"]["voltage_ch3"] = decoded->variant.power_metrics.ch3_voltage; jsonObj["payload"]["pm25_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_environmental;
jsonObj["payload"]["current_ch3"] = decoded->variant.power_metrics.ch3_current; jsonObj["payload"]["pm100_e"] = (unsigned int)decoded->variant.air_quality_metrics.pm100_environmental;
} }
} else if (shouldLog) { else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag)
LOG_ERROR("Error decoding protobuf for telemetry message!\n"); {
return ""; jsonObj["payload"]["voltage_ch1"] = decoded->variant.power_metrics.ch1_voltage;
} jsonObj["payload"]["current_ch1"] = decoded->variant.power_metrics.ch1_current;
break; jsonObj["payload"]["voltage_ch2"] = decoded->variant.power_metrics.ch2_voltage;
} jsonObj["payload"]["current_ch2"] = decoded->variant.power_metrics.ch2_current;
case meshtastic_PortNum_NODEINFO_APP: { jsonObj["payload"]["voltage_ch3"] = decoded->variant.power_metrics.ch3_voltage;
msgType = "nodeinfo"; jsonObj["payload"]["current_ch3"] = decoded->variant.power_metrics.ch3_current;
meshtastic_User scratch; }
meshtastic_User *decoded = NULL; }
memset(&scratch, 0, sizeof(scratch)); else if (shouldLog)
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) { {
decoded = &scratch; LOG_ERROR("Error decoding protobuf for telemetry message!\n");
jsonObj["payload"]["id"] = decoded->id; return "";
jsonObj["payload"]["longname"] = decoded->long_name; }
jsonObj["payload"]["shortname"] = decoded->short_name; break;
jsonObj["payload"]["hardware"] = decoded->hw_model; }
jsonObj["payload"]["role"] = (int)decoded->role; case meshtastic_PortNum_NODEINFO_APP:
} else if (shouldLog) { {
LOG_ERROR("Error decoding protobuf for nodeinfo message!\n"); msgType = "nodeinfo";
return ""; meshtastic_User scratch;
} meshtastic_User *decoded = NULL;
break; memset(&scratch, 0, sizeof(scratch));
} if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch))
case meshtastic_PortNum_POSITION_APP: { {
msgType = "position"; decoded = &scratch;
meshtastic_Position scratch; jsonObj["payload"]["id"] = decoded->id;
meshtastic_Position *decoded = NULL; jsonObj["payload"]["longname"] = decoded->long_name;
memset(&scratch, 0, sizeof(scratch)); jsonObj["payload"]["shortname"] = decoded->short_name;
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) { jsonObj["payload"]["hardware"] = decoded->hw_model;
decoded = &scratch; jsonObj["payload"]["role"] = (int)decoded->role;
if ((int)decoded->time) { }
jsonObj["payload"]["time"] = (unsigned int)decoded->time; else if (shouldLog)
} {
if ((int)decoded->timestamp) { LOG_ERROR("Error decoding protobuf for nodeinfo message!\n");
jsonObj["payload"]["timestamp"] = (unsigned int)decoded->timestamp; return "";
} }
jsonObj["payload"]["latitude_i"] = (int)decoded->latitude_i; break;
jsonObj["payload"]["longitude_i"] = (int)decoded->longitude_i; }
if ((int)decoded->altitude) { case meshtastic_PortNum_POSITION_APP:
jsonObj["payload"]["altitude"] = (int)decoded->altitude; {
} msgType = "position";
if ((int)decoded->ground_speed) { meshtastic_Position scratch;
jsonObj["payload"]["ground_speed"] = (unsigned int)decoded->ground_speed; meshtastic_Position *decoded = NULL;
} memset(&scratch, 0, sizeof(scratch));
if (int(decoded->ground_track)) { if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch))
jsonObj["payload"]["ground_track"] = (unsigned int)decoded->ground_track; {
} decoded = &scratch;
if (int(decoded->sats_in_view)) { if ((int)decoded->time)
jsonObj["payload"]["sats_in_view"] = (unsigned int)decoded->sats_in_view; {
} jsonObj["payload"]["time"] = (unsigned int)decoded->time;
if ((int)decoded->PDOP) { }
jsonObj["payload"]["PDOP"] = (int)decoded->PDOP; if ((int)decoded->timestamp)
} {
if ((int)decoded->HDOP) { jsonObj["payload"]["timestamp"] = (unsigned int)decoded->timestamp;
jsonObj["payload"]["HDOP"] = (int)decoded->HDOP; }
} jsonObj["payload"]["latitude_i"] = (int)decoded->latitude_i;
if ((int)decoded->VDOP) { jsonObj["payload"]["longitude_i"] = (int)decoded->longitude_i;
jsonObj["payload"]["VDOP"] = (int)decoded->VDOP; if ((int)decoded->altitude)
} {
if ((int)decoded->precision_bits) { jsonObj["payload"]["altitude"] = (int)decoded->altitude;
jsonObj["payload"]["precision_bits"] = (int)decoded->precision_bits; }
} if ((int)decoded->ground_speed)
} else if (shouldLog) { {
LOG_ERROR("Error decoding protobuf for position message!\n"); jsonObj["payload"]["ground_speed"] = (unsigned int)decoded->ground_speed;
return ""; }
} if (int(decoded->ground_track))
break; {
} jsonObj["payload"]["ground_track"] = (unsigned int)decoded->ground_track;
case meshtastic_PortNum_WAYPOINT_APP: { }
msgType = "position"; if (int(decoded->sats_in_view))
meshtastic_Waypoint scratch; {
meshtastic_Waypoint *decoded = NULL; jsonObj["payload"]["sats_in_view"] = (unsigned int)decoded->sats_in_view;
memset(&scratch, 0, sizeof(scratch)); }
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) { if ((int)decoded->PDOP)
decoded = &scratch; {
jsonObj["payload"]["id"] = (unsigned int)decoded->id; jsonObj["payload"]["PDOP"] = (int)decoded->PDOP;
jsonObj["payload"]["name"] = decoded->name; }
jsonObj["payload"]["description"] = decoded->description; if ((int)decoded->HDOP)
jsonObj["payload"]["expire"] = (unsigned int)decoded->expire; {
jsonObj["payload"]["locked_to"] = (unsigned int)decoded->locked_to; jsonObj["payload"]["HDOP"] = (int)decoded->HDOP;
jsonObj["payload"]["latitude_i"] = (int)decoded->latitude_i; }
jsonObj["payload"]["longitude_i"] = (int)decoded->longitude_i; if ((int)decoded->VDOP)
} else if (shouldLog) { {
LOG_ERROR("Error decoding protobuf for position message!\n"); jsonObj["payload"]["VDOP"] = (int)decoded->VDOP;
return ""; }
} if ((int)decoded->precision_bits)
break; {
} jsonObj["payload"]["precision_bits"] = (int)decoded->precision_bits;
case meshtastic_PortNum_NEIGHBORINFO_APP: { }
msgType = "neighborinfo"; }
meshtastic_NeighborInfo scratch; else if (shouldLog)
meshtastic_NeighborInfo *decoded = NULL; {
memset(&scratch, 0, sizeof(scratch)); LOG_ERROR("Error decoding protobuf for position message!\n");
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg, return "";
&scratch)) { }
decoded = &scratch; break;
jsonObj["payload"]["node_id"] = (unsigned int)decoded->node_id; }
jsonObj["payload"]["node_broadcast_interval_secs"] = (unsigned int)decoded->node_broadcast_interval_secs; case meshtastic_PortNum_WAYPOINT_APP:
jsonObj["payload"]["last_sent_by_id"] = (unsigned int)decoded->last_sent_by_id; {
jsonObj["payload"]["neighbors_count"] = decoded->neighbors_count; msgType = "position";
meshtastic_Waypoint scratch;
meshtastic_Waypoint *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch))
{
decoded = &scratch;
jsonObj["payload"]["id"] = (unsigned int)decoded->id;
jsonObj["payload"]["name"] = decoded->name;
jsonObj["payload"]["description"] = decoded->description;
jsonObj["payload"]["expire"] = (unsigned int)decoded->expire;
jsonObj["payload"]["locked_to"] = (unsigned int)decoded->locked_to;
jsonObj["payload"]["latitude_i"] = (int)decoded->latitude_i;
jsonObj["payload"]["longitude_i"] = (int)decoded->longitude_i;
}
else if (shouldLog)
{
LOG_ERROR("Error decoding protobuf for position message!\n");
return "";
}
break;
}
case meshtastic_PortNum_NEIGHBORINFO_APP:
{
msgType = "neighborinfo";
meshtastic_NeighborInfo scratch;
meshtastic_NeighborInfo *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg,
&scratch))
{
decoded = &scratch;
jsonObj["payload"]["node_id"] = (unsigned int)decoded->node_id;
jsonObj["payload"]["node_broadcast_interval_secs"] = (unsigned int)decoded->node_broadcast_interval_secs;
jsonObj["payload"]["last_sent_by_id"] = (unsigned int)decoded->last_sent_by_id;
jsonObj["payload"]["neighbors_count"] = decoded->neighbors_count;
JsonObject neighbors_obj = arrayObj.to<JsonObject>(); JsonObject neighbors_obj = arrayObj.to<JsonObject>();
JsonArray neighbors = neighbors_obj.createNestedArray("neighbors"); JsonArray neighbors = neighbors_obj.createNestedArray("neighbors");
JsonObject neighbors_0 = neighbors.createNestedObject(); JsonObject neighbors_0 = neighbors.createNestedObject();
for (uint8_t i = 0; i < decoded->neighbors_count; i++) { for (uint8_t i = 0; i < decoded->neighbors_count; i++)
neighbors_0["node_id"] = (unsigned int)decoded->neighbors[i].node_id; {
neighbors_0["snr"] = (int)decoded->neighbors[i].snr; neighbors_0["node_id"] = (unsigned int)decoded->neighbors[i].node_id;
neighbors[i+1] = neighbors_0; neighbors_0["snr"] = (int)decoded->neighbors[i].snr;
neighbors_0.clear(); neighbors[i + 1] = neighbors_0;
} neighbors_0.clear();
}
neighbors.remove(0); neighbors.remove(0);
jsonObj["payload"]["neighbors"] = neighbors; jsonObj["payload"]["neighbors"] = neighbors;
} else if (shouldLog) { }
LOG_ERROR("Error decoding protobuf for neighborinfo message!\n"); else if (shouldLog)
return ""; {
} LOG_ERROR("Error decoding protobuf for neighborinfo message!\n");
break;
}
case meshtastic_PortNum_TRACEROUTE_APP: {
if (mp->decoded.request_id) { // Only report the traceroute response
msgType = "traceroute";
meshtastic_RouteDiscovery scratch;
meshtastic_RouteDiscovery *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg,
&scratch)) {
decoded = &scratch;
JsonArray route = arrayObj.createNestedArray("route");
auto addToRoute = [](JsonArray *route, NodeNum num) {
char long_name[40] = "Unknown";
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num);
bool name_known = node ? node->has_user : false;
if (name_known)
memcpy(long_name, node->user.long_name, sizeof(long_name));
route->add(long_name);
};
addToRoute(&route,mp->to); //route.add(mp->to);
for (uint8_t i = 0; i < decoded->route_count; i++) {
addToRoute(&route,decoded->route[i]); //route.add(decoded->route[i]);
}
addToRoute(&route,mp->from); //route.add(mp->from); // Ended at the original destination (source of response)
jsonObj["payload"]["route"] = route;
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for traceroute message!\n");
return "";
}
} else {
LOG_WARN("Traceroute response not reported");
return ""; return "";
} }
break; break;
} }
case meshtastic_PortNum_DETECTION_SENSOR_APP: { case meshtastic_PortNum_TRACEROUTE_APP:
msgType = "detection"; {
char payloadStr[(mp->decoded.payload.size) + 1]; if (mp->decoded.request_id)
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size); { // Only report the traceroute response
payloadStr[mp->decoded.payload.size] = 0; // null terminated string msgType = "traceroute";
jsonObj["payload"]["text"] = payloadStr; meshtastic_RouteDiscovery scratch;
break; meshtastic_RouteDiscovery *decoded = NULL;
} memset(&scratch, 0, sizeof(scratch));
case meshtastic_PortNum_REMOTE_HARDWARE_APP: { if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg,
meshtastic_HardwareMessage scratch; &scratch))
meshtastic_HardwareMessage *decoded = NULL; {
memset(&scratch, 0, sizeof(scratch)); decoded = &scratch;
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg, JsonArray route = arrayObj.createNestedArray("route");
&scratch)) {
decoded = &scratch; auto addToRoute = [](JsonArray *route, NodeNum num)
if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED) { {
msgType = "gpios_changed"; char long_name[40] = "Unknown";
jsonObj["payload"]["gpio_value"] = (unsigned int)decoded->gpio_value; meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num);
} else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY) { bool name_known = node ? node->has_user : false;
msgType = "gpios_read_reply"; if (name_known)
jsonObj["payload"]["gpio_value"] = (unsigned int)decoded->gpio_value; memcpy(long_name, node->user.long_name, sizeof(long_name));
jsonObj["payload"]["gpio_mask"] = (unsigned int)decoded->gpio_mask; route->add(long_name);
} };
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for RemoteHardware message!\n"); addToRoute(&route, mp->to); // route.add(mp->to);
return ""; for (uint8_t i = 0; i < decoded->route_count; i++)
} {
break; addToRoute(&route, decoded->route[i]); // route.add(decoded->route[i]);
} }
// add more packet types here if needed addToRoute(&route, mp->from); // route.add(mp->from); // Ended at the original destination (source of response)
default:
LOG_WARN("Unsupported packet type %d\n",mp->decoded.portnum); jsonObj["payload"]["route"] = route;
}
else if (shouldLog)
{
LOG_ERROR("Error decoding protobuf for traceroute message!\n");
return "";
}
}
else
{
LOG_WARN("Traceroute response not reported");
return "";
}
break;
}
case meshtastic_PortNum_DETECTION_SENSOR_APP:
{
msgType = "detection";
char payloadStr[(mp->decoded.payload.size) + 1];
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
jsonObj["payload"]["text"] = payloadStr;
break;
}
case meshtastic_PortNum_REMOTE_HARDWARE_APP:
{
meshtastic_HardwareMessage scratch;
meshtastic_HardwareMessage *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg,
&scratch))
{
decoded = &scratch;
if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED)
{
msgType = "gpios_changed";
jsonObj["payload"]["gpio_value"] = (unsigned int)decoded->gpio_value;
}
else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY)
{
msgType = "gpios_read_reply";
jsonObj["payload"]["gpio_value"] = (unsigned int)decoded->gpio_value;
jsonObj["payload"]["gpio_mask"] = (unsigned int)decoded->gpio_mask;
}
}
else if (shouldLog)
{
LOG_ERROR("Error decoding protobuf for RemoteHardware message!\n");
return "";
}
break;
}
// add more packet types here if needed
default:
LOG_WARN("Unsupported packet type %d\n", mp->decoded.portnum);
return ""; return "";
break; break;
} }
} else if (shouldLog) { }
LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON\n"); else if (shouldLog)
{
LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON\n");
return ""; return "";
} }
jsonObj["id"] = (unsigned int)mp->id; jsonObj["id"] = (unsigned int)mp->id;
jsonObj["timestamp"] = (unsigned int)mp->rx_time; jsonObj["timestamp"] = (unsigned int)mp->rx_time;
jsonObj["to"] = (unsigned int)mp->to; jsonObj["to"] = (unsigned int)mp->to;
jsonObj["from"] = (unsigned int)mp->from; jsonObj["from"] = (unsigned int)mp->from;
jsonObj["channel"] = (unsigned int)mp->channel; jsonObj["channel"] = (unsigned int)mp->channel;
jsonObj["type"] = msgType.c_str(); jsonObj["type"] = msgType.c_str();
jsonObj["sender"] = owner.id; jsonObj["sender"] = owner.id;
if (mp->rx_rssi != 0) if (mp->rx_rssi != 0)
jsonObj["rssi"] = (int)mp->rx_rssi; jsonObj["rssi"] = (int)mp->rx_rssi;
if (mp->rx_snr != 0) if (mp->rx_snr != 0)
jsonObj["snr"] = (float)mp->rx_snr; jsonObj["snr"] = (float)mp->rx_snr;
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) { if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start)
jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit); {
jsonObj["hop_start"] = (unsigned int)(mp->hop_start); jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit);
} jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
}
// serialize and write it to the stream // serialize and write it to the stream
// Serial.printf("serialized json message: \r\n"); // Serial.printf("serialized json message: \r\n");
// serializeJson(jsonObj, Serial); // serializeJson(jsonObj, Serial);
@ -314,39 +378,40 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp,
std::string jsonStr = ""; std::string jsonStr = "";
serializeJson(jsonObj, jsonStr); serializeJson(jsonObj, jsonStr);
if (shouldLog) if (shouldLog)
LOG_INFO("serialized json message: %s\n", jsonStr.c_str()); LOG_INFO("serialized json message: %s\n", jsonStr.c_str());
return jsonStr; return jsonStr;
} }
std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPacket *mp) std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPacket *mp)
{ {
jsonObj.clear(); jsonObj.clear();
jsonObj["id"] = (unsigned int)mp->id; jsonObj["id"] = (unsigned int)mp->id;
jsonObj["time_ms"] = (double)millis(); jsonObj["time_ms"] = (double)millis();
jsonObj["timestamp"] = (unsigned int)mp->rx_time; jsonObj["timestamp"] = (unsigned int)mp->rx_time;
jsonObj["to"] = (unsigned int)mp->to; jsonObj["to"] = (unsigned int)mp->to;
jsonObj["from"] = (unsigned int)mp->from; jsonObj["from"] = (unsigned int)mp->from;
jsonObj["channel"] = (unsigned int)mp->channel; jsonObj["channel"] = (unsigned int)mp->channel;
jsonObj["want_ack"] = mp->want_ack; jsonObj["want_ack"] = mp->want_ack;
if (mp->rx_rssi != 0) if (mp->rx_rssi != 0)
jsonObj["rssi"] = (int)mp->rx_rssi; jsonObj["rssi"] = (int)mp->rx_rssi;
if (mp->rx_snr != 0) if (mp->rx_snr != 0)
jsonObj["snr"] = (float)mp->rx_snr; jsonObj["snr"] = (float)mp->rx_snr;
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) { if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start)
jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit); {
jsonObj["hop_start"] = (unsigned int)(mp->hop_start); jsonObj["hops_away"] = (unsigned int)(mp->hop_start - mp->hop_limit);
} jsonObj["hop_start"] = (unsigned int)(mp->hop_start);
jsonObj["size"] = (unsigned int)mp->encrypted.size; }
auto encryptedStr = bytesToHex(mp->encrypted.bytes, mp->encrypted.size); jsonObj["size"] = (unsigned int)mp->encrypted.size;
jsonObj["bytes"] = encryptedStr.c_str(); auto encryptedStr = bytesToHex(mp->encrypted.bytes, mp->encrypted.size);
jsonObj["bytes"] = encryptedStr.c_str();
// serialize and write it to the stream // serialize and write it to the stream
std::string jsonStr = ""; std::string jsonStr = "";
serializeJson(jsonObj, jsonStr); serializeJson(jsonObj, jsonStr);
return jsonStr; return jsonStr;
} }
#endif #endif