Merge pull request #10 from meshtastic/master

update my fork from head
This commit is contained in:
Jm Casler 2020-09-25 16:40:01 -07:00 committed by GitHub
commit 7fdb5b594d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 221 additions and 141 deletions

View File

@ -56,6 +56,7 @@
"HFSR", "HFSR",
"Meshtastic", "Meshtastic",
"NEMAGPS", "NEMAGPS",
"RDEF",
"Ublox", "Ublox",
"bkpt", "bkpt",
"cfsr", "cfsr",

View File

@ -1,7 +1,7 @@
theme: jekyll-theme-cayman theme: jekyll-theme-cayman
title: Meshtastic title: Meshtastic
description: An opensource hiking, pilot, skiing, Signal-App-extending GPS mesh communicator description: An opensource hiking, pilot, skiing, secure GPS mesh communicator
google_analytics: G-DRZ5H5EXHV google_analytics: G-DRZ5H5EXHV
include: [".well-known"] include: [".well-known"]

View File

@ -32,11 +32,15 @@ From lower to higher power consumption.
onEntry: setBluetoothOn(true) onEntry: setBluetoothOn(true)
onExit: onExit:
- full on (ON) - Everything is on - serial API usage (SERIAL) - Screen is on, device doesn't sleep, bluetooth off
onEntry: setBluetooth off, screen on
onExit:
- full on (ON) - Everything is on, can eventually timeout and lower to a lower power state
onEntry: setBluetoothOn(true), screen.setOn(true) onEntry: setBluetoothOn(true), screen.setOn(true)
onExit: screen.setOn(false) onExit: screen.setOn(false)
- serial API usage (SERIAL) - Screen is on, device doesn't sleep, bluetooth off - has power (POWER) - Screen is on, device doesn't sleep, bluetooth on, will stay in this state as long as we have power
onEntry: setBluetooth off, screen on onEntry: setBluetooth off, screen on
onExit: onExit:
@ -56,9 +60,11 @@ From lower to higher power consumption.
- While in NB/DARK/ON: If we receive EVENT_NODEDB_UPDATED we transition to ON (so the new screen can be shown) - While in NB/DARK/ON: If we receive EVENT_NODEDB_UPDATED we transition to ON (so the new screen can be shown)
- While in DARK: While the phone talks to us over BLE (EVENT_CONTACT_FROM_PHONE) reset any sleep timers and stay in DARK (needed for bluetooth sw update and nice user experience if the user is reading/replying to texts) - While in DARK: While the phone talks to us over BLE (EVENT_CONTACT_FROM_PHONE) reset any sleep timers and stay in DARK (needed for bluetooth sw update and nice user experience if the user is reading/replying to texts)
- while in LS/NB/DARK: if SERIAL_CONNECTED, go to serial - while in LS/NB/DARK: if SERIAL_CONNECTED, go to serial
- while in any state: if we have AC power, go to POWER
### events that decrease cpu activity ### events that decrease cpu activity
- While in POWER: if lose AC go to ON
- While in SERIAL: if SERIAL_DISCONNECTED, go to NB - While in SERIAL: if SERIAL_DISCONNECTED, go to NB
- While in ON: If PRESS event occurs, reset screen_on_secs timer and tell the screen to handle the pess - While in ON: If PRESS event occurs, reset screen_on_secs timer and tell the screen to handle the pess
- While in ON: If it has been more than screen_on_secs since a press, lower to DARK - While in ON: If it has been more than screen_on_secs since a press, lower to DARK

View File

@ -5,5 +5,5 @@ This is a mini design doc for developing the meshtastic software.
* Our [project board](https://github.com/orgs/meshtastic/projects/1) - shows what things we are currently working on and remaining work items for the current release. * Our [project board](https://github.com/orgs/meshtastic/projects/1) - shows what things we are currently working on and remaining work items for the current release.
* [Power Management](power.md) * [Power Management](power.md)
* [Mesh algorithm](mesh-alg.md) * [Mesh algorithm](mesh-alg.md)
* [Bluetooth API](bluetooth-api.md) and porting guide for new clients (iOS, python, etc...) * [Device API](device-api.md) and porting guide for new clients (iOS, python, etc...)
* TODO: how to port the device code to a new device. * TODO: how to port the device code to a new device.

View File

@ -172,7 +172,7 @@ build_flags =
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3 -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3
;-DCFG_DEBUG=3 ;-DCFG_DEBUG=3
src_filter = src_filter =
${env.src_filter} -<esp32/> -<nimble/> -<meshwifi/> ${arduino_base.src_filter} -<esp32/> -<nimble/> -<meshwifi/>
lib_ignore = lib_ignore =
BluetoothOTA BluetoothOTA
monitor_port = /dev/ttyACM1 monitor_port = /dev/ttyACM1
@ -253,7 +253,7 @@ lib_deps =
; The Portduino based sim environment on top of linux ; The Portduino based sim environment on top of linux
[env:linux] [env:linux]
platform = https://github.com/geeksville/platform-portduino.git platform = https://github.com/geeksville/platform-portduino.git
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<meshwifi/>
build_flags = ${arduino_base.build_flags} -O0 build_flags = ${arduino_base.build_flags} -O0
framework = arduino framework = arduino
board = linux_x86_64 board = linux_x86_64

2
proto

@ -1 +1 @@
Subproject commit 4e431c841015edfdde925acf5ee4ac0a2272edff Subproject commit 5cdd7bff56b0ea54351e5ea0e358e864b061078f

View File

@ -119,6 +119,7 @@ void Power::readPowerStatus()
const PowerStatus powerStatus = const PowerStatus powerStatus =
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse, PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse,
batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent); batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
DEBUG_MSG("Read power stat %d\n", powerStatus.getHasUSB());
newStatus.notifyObservers(&powerStatus); newStatus.notifyObservers(&powerStatus);
// If we have a battery at all and it is less than 10% full, force deep sleep // If we have a battery at all and it is less than 10% full, force deep sleep
@ -237,9 +238,11 @@ void Power::loop()
} }
if (axp.isVbusRemoveIRQ()) { if (axp.isVbusRemoveIRQ()) {
DEBUG_MSG("USB unplugged\n"); DEBUG_MSG("USB unplugged\n");
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
} }
if (axp.isVbusPlugInIRQ()) { if (axp.isVbusPlugInIRQ()) {
DEBUG_MSG("USB plugged In\n"); DEBUG_MSG("USB plugged In\n");
powerFSM.trigger(EVENT_POWER_CONNECTED);
} }
if (axp.isBattPlugInIRQ()) { if (axp.isBattPlugInIRQ()) {
DEBUG_MSG("Battery inserted\n"); DEBUG_MSG("Battery inserted\n");

View File

@ -4,8 +4,8 @@
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "configuration.h" #include "configuration.h"
#include "main.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "main.h"
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
@ -123,6 +123,12 @@ static void serialEnter()
screen.setOn(true); screen.setOn(true);
} }
static void powerEnter()
{
screen.setOn(true);
setBluetoothEnable(true);
}
static void onEnter() static void onEnter()
{ {
screen.setOn(true); screen.setOn(true);
@ -155,16 +161,20 @@ State stateDARK(darkEnter, NULL, NULL, "DARK");
State stateSERIAL(serialEnter, NULL, NULL, "SERIAL"); State stateSERIAL(serialEnter, NULL, NULL, "SERIAL");
State stateBOOT(bootEnter, NULL, NULL, "BOOT"); State stateBOOT(bootEnter, NULL, NULL, "BOOT");
State stateON(onEnter, NULL, NULL, "ON"); State stateON(onEnter, NULL, NULL, "ON");
State statePOWER(powerEnter, NULL, NULL, "POWER");
Fsm powerFSM(&stateBOOT); Fsm powerFSM(&stateBOOT);
void PowerFSM_setup() void PowerFSM_setup()
{ {
powerFSM.add_timed_transition(&stateBOOT, &stateON, 3 * 1000, NULL, "boot timeout"); // If we already have AC power go to POWER state after init, otherwise go to ON
bool hasPower = powerStatus && powerStatus->getHasUSB();
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer"); powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer");
// Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB and then it // Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB and then
// handles things powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet"); // it handles things powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet");
powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake"); powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake");
@ -172,7 +182,10 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press");
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress,
"Press"); // Allow button to work while in serial API
// Handle critically low power battery by forcing deep sleep // Handle critically low power battery by forcing deep sleep
powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
@ -199,6 +212,14 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API"); powerFSM.add_transition(&stateDARK, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
powerFSM.add_transition(&stateON, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API"); powerFSM.add_transition(&stateON, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
powerFSM.add_transition(&stateLS, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
powerFSM.add_transition(&stateNB, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
powerFSM.add_transition(&stateDARK, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
powerFSM.add_transition(&stateON, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
powerFSM.add_transition(&statePOWER, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
powerFSM.add_transition(&stateSERIAL, &stateNB, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect"); powerFSM.add_transition(&stateSERIAL, &stateNB, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect");
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone"); powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");

View File

@ -16,6 +16,8 @@
#define EVENT_LOW_BATTERY 10 // Battery is critically low, go to sleep #define EVENT_LOW_BATTERY 10 // Battery is critically low, go to sleep
#define EVENT_SERIAL_CONNECTED 11 #define EVENT_SERIAL_CONNECTED 11
#define EVENT_SERIAL_DISCONNECTED 12 #define EVENT_SERIAL_DISCONNECTED 12
#define EVENT_POWER_CONNECTED 13
#define EVENT_POWER_DISCONNECTED 14
extern Fsm powerFSM; extern Fsm powerFSM;

View File

@ -40,6 +40,8 @@ void SerialConsole::onConnectionChanged(bool connected)
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
powerFSM.trigger(EVENT_SERIAL_CONNECTED); powerFSM.trigger(EVENT_SERIAL_CONNECTED);
} else { } else {
// FIXME, we get no notice of serial going away, we should instead automatically generate this event if we haven't
// received a packet in a while
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED); powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
} }
} }

View File

@ -52,6 +52,14 @@ void WiFiServerPort::loop()
{ {
auto client = available(); auto client = available();
if (client) { if (client) {
new WiFiServerAPI(client); // Close any previous connection (see FIXME in header file)
if (openAPI)
delete openAPI;
openAPI = new WiFiServerAPI(client);
} }
if (openAPI)
// Allow idle processing so the API can read from its incoming stream
openAPI->loop();
} }

View File

@ -29,6 +29,13 @@ class WiFiServerAPI : public StreamAPI
*/ */
class WiFiServerPort : public WiFiServer class WiFiServerPort : public WiFiServer
{ {
/** The currently open port
*
* FIXME: We currently only allow one open TCP connection at a time, because we depend on the loop() call in this class to
* delegate to the worker. Once coroutines are implemented we can relax this restriction.
*/
WiFiServerAPI *openAPI = NULL;
public: public:
WiFiServerPort(); WiFiServerPort();

View File

@ -31,8 +31,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graphics/images.h" #include "graphics/images.h"
#include "main.h" #include "main.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include "target_specific.h"
#include "meshwifi/meshwifi.h" #include "meshwifi/meshwifi.h"
#include "target_specific.h"
#include "utils.h" #include "utils.h"
using namespace meshtastic; /** @todo remove */ using namespace meshtastic; /** @todo remove */
@ -809,6 +809,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
{ {
concurrency::LockGuard guard(&lock); concurrency::LockGuard guard(&lock);
snprintf(channelStr, sizeof(channelStr), "%s", channelName.c_str()); snprintf(channelStr, sizeof(channelStr), "%s", channelName.c_str());
}
// Display power status // Display power status
if (powerStatus->getHasBattery()) if (powerStatus->getHasBattery())
@ -819,7 +820,6 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus); drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus);
// Display GPS status // Display GPS status
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus); drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
}
// Draw the channel name // Draw the channel name
display->drawString(x, y + FONT_HEIGHT, channelStr); display->drawString(x, y + FONT_HEIGHT, channelStr);

View File

@ -215,9 +215,9 @@ void setup()
// Currently only the tbeam has a PMU // Currently only the tbeam has a PMU
power = new Power(); power = new Power();
power->setup();
power->setStatusHandler(powerStatus); power->setStatusHandler(powerStatus);
powerStatus->observe(&power->newStatus); powerStatus->observe(&power->newStatus);
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
#ifdef NRF52_SERIES #ifdef NRF52_SERIES
nrf52Setup(); nrf52Setup();

View File

@ -6,87 +6,14 @@
#include "configuration.h" #include "configuration.h"
#include "mesh.pb.h" #include "mesh.pb.h"
// US channel settings // Map from old region names to new region enums
#define CH0_US 903.08f // MHz struct RegionInfo {
#define CH_SPACING_US 2.16f // MHz RegionCode code;
#define NUM_CHANNELS_US 13 uint8_t numChannels;
uint8_t powerLimit; // Or zero for not set
float freq;
float spacing;
const char *name; // EU433 etc
};
// EU433 channel settings extern const RegionInfo regions[];
#define CH0_EU433 433.175f // MHz
#define CH_SPACING_EU433 0.2f // MHz
#define NUM_CHANNELS_EU433 8
// EU865 channel settings
#define CH0_EU865 865.2f // MHz
#define CH_SPACING_EU865 0.3f // MHz
#define NUM_CHANNELS_EU865 10
// CN channel settings
#define CH0_CN 470.0f // MHz
#define CH_SPACING_CN 2.0f // MHz FIXME, this is just a guess for 470-510
#define NUM_CHANNELS_CN 20
// JP channel settings (AS1 bandplan)
#define CH0_JP 920.0f // MHz
#define CH_SPACING_JP 0.5f
#define NUM_CHANNELS_JP 10
// TW channel settings (AS2 bandplan 923-925MHz)
#define CH0_TW 923.0f // MHz
#define CH_SPACING_TW 0.2
#define NUM_CHANNELS_TW 10
// AU/NZ channel settings 915-928MHz
#define CH0_ANZ 916.0f // MHz - avoid overcrowding on 915.0
#define CH_SPACING_ANZ 0.5f
#define NUM_CHANNELS_ANZ 20
// KR channel settings (KR920-923)
// Start from TTN download channel freq. (921.9f is for download, others are for uplink)
#define CH0_KR 921.9f // MHz
#define CH_SPACING_KR 0.2f
#define NUM_CHANNELS_KR 8
// FIXME add defs for other regions and use them here
#ifdef HW_VERSION_US
#define CH0 CH0_US
#define CH_SPACING CH_SPACING_US
#define NUM_CHANNELS NUM_CHANNELS_US
#elif defined(HW_VERSION_EU433)
#define CH0 CH0_EU433
#define CH_SPACING CH_SPACING_EU433
#define NUM_CHANNELS NUM_CHANNELS_EU433
#elif defined(HW_VERSION_EU865)
#define CH0 CH0_EU865
#define CH_SPACING CH_SPACING_EU865
#define NUM_CHANNELS NUM_CHANNELS_EU865
#elif defined(HW_VERSION_CN)
#define CH0 CH0_CN
#define CH_SPACING CH_SPACING_CN
#define NUM_CHANNELS NUM_CHANNELS_CN
#elif defined(HW_VERSION_JP)
// Also called AS1 bandplan
#define CH0 CH0_JP
#define CH_SPACING CH_SPACING_JP
#define NUM_CHANNELS NUM_CHANNELS_JP
#elif defined(HW_VERSION_TW)
// Also called AS2 bandplan
#define CH0 CH0_TW
#define CH_SPACING CH_SPACING_TW
#define NUM_CHANNELS NUM_CHANNELS_TW
#elif defined(HW_VERSION_ANZ)
// Australia and NZ
#define CH0 CH0_ANZ
#define CH_SPACING CH_SPACING_ANZ
#define NUM_CHANNELS NUM_CHANNELS_ANZ
#elif defined(HW_VERSION_KR)
// Republic of Korea
#define CH0 CH0_KR
#define CH_SPACING CH_SPACING_KR
#define NUM_CHANNELS NUM_CHANNELS_KR
#else
// HW version not set - assume US
#define CH0 CH0_US
#define CH_SPACING CH_SPACING_US
#define NUM_CHANNELS NUM_CHANNELS_US
#endif

View File

@ -197,12 +197,14 @@ void MeshService::loop()
} }
/// The radioConfig object just changed, call this to force the hw to change to the new settings /// The radioConfig object just changed, call this to force the hw to change to the new settings
void MeshService::reloadConfig() bool MeshService::reloadConfig()
{ {
// If we can successfully set this radio to these settings, save them to disk // If we can successfully set this radio to these settings, save them to disk
nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings bool didReset = nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
configChanged.notifyObservers(NULL); configChanged.notifyObservers(NULL);
nodeDB.saveToDisk(); nodeDB.saveToDisk();
return didReset;
} }
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh /// The owner User record just got updated, update our node DB and broadcast the info into the mesh

View File

@ -63,8 +63,10 @@ class MeshService
*/ */
void handleToRadio(MeshPacket &p); void handleToRadio(MeshPacket &p);
/// The radioConfig object just changed, call this to force the hw to change to the new settings /** The radioConfig object just changed, call this to force the hw to change to the new settings
void reloadConfig(); * @return true if client devices should be sent a new set of radio configs
*/
bool reloadConfig();
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh /// The owner User record just got updated, update our node DB and broadcast the info into the mesh
void reloadOwner(); void reloadOwner();

View File

@ -6,6 +6,7 @@
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "GPS.h" #include "GPS.h"
#include "MeshRadio.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "PacketHistory.h" #include "PacketHistory.h"
#include "PowerFSM.h" #include "PowerFSM.h"
@ -13,9 +14,9 @@
#include "configuration.h" #include "configuration.h"
#include "error.h" #include "error.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include "meshwifi/meshwifi.h"
#include <pb_decode.h> #include <pb_decode.h>
#include <pb_encode.h> #include <pb_encode.h>
#include "meshwifi/meshwifi.h"
NodeDB nodeDB; NodeDB nodeDB;
@ -103,14 +104,21 @@ const char *getChannelName()
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {} NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
void NodeDB::resetRadioConfig() bool NodeDB::resetRadioConfig()
{ {
bool didFactoryReset = false;
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128) /// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128)
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf}; 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
if (radioConfig.preferences.sds_secs == 0) { if (radioConfig.preferences.factory_reset) {
DEBUG_MSG("RadioConfig reset!\n"); DEBUG_MSG("Performing factory reset!\n");
installDefaultDeviceState();
didFactoryReset = true;
} else if (radioConfig.preferences.sds_secs == 0) {
DEBUG_MSG("Fixing bogus RadioConfig!\n");
radioConfig.preferences.send_owner_interval = 4; // per sw-design.md radioConfig.preferences.send_owner_interval = 4; // per sw-design.md
radioConfig.preferences.position_broadcast_secs = 15 * 60; radioConfig.preferences.position_broadcast_secs = 15 * 60;
radioConfig.preferences.wait_bluetooth_secs = 120; radioConfig.preferences.wait_bluetooth_secs = 120;
@ -124,8 +132,8 @@ void NodeDB::resetRadioConfig()
radioConfig.has_preferences = true; radioConfig.has_preferences = true;
// radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast // radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
// channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide bandwidth // channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide
// so incompatible radios can talk together // bandwidth so incompatible radios can talk together
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
channelSettings.tx_power = 0; // default channelSettings.tx_power = 0; // default
@ -148,12 +156,20 @@ void NodeDB::resetRadioConfig()
radioConfig.preferences.position_broadcast_secs = 6 * 60; radioConfig.preferences.position_broadcast_secs = 6 * 60;
radioConfig.preferences.ls_secs = 60; radioConfig.preferences.ls_secs = 60;
} }
return didFactoryReset;
} }
void NodeDB::installDefaultDeviceState() void NodeDB::installDefaultDeviceState()
{ {
// We try to preserve the region setting because it will really bum users out if we discard it
String oldRegion = myNodeInfo.region;
RegionCode oldRegionCode = radioConfig.preferences.region;
memset(&devicestate, 0, sizeof(devicestate)); memset(&devicestate, 0, sizeof(devicestate));
*numNodes = 0; // Forget node DB
// init our devicestate with valid flags so protobuf writing/reading will work // init our devicestate with valid flags so protobuf writing/reading will work
devicestate.has_my_node = true; devicestate.has_my_node = true;
devicestate.has_radio = true; devicestate.has_radio = true;
@ -182,6 +198,12 @@ void NodeDB::installDefaultDeviceState()
// owner.short_name now // owner.short_name now
sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]); sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]);
sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff)); sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff));
// Restore region if possible
if (oldRegionCode != RegionCode_Unset)
radioConfig.preferences.region = oldRegionCode;
if (oldRegion.length())
strcpy(myNodeInfo.region, oldRegion.c_str());
} }
void NodeDB::init() void NodeDB::init()
@ -214,13 +236,29 @@ void NodeDB::init()
// We set these _after_ loading from disk - because they come from the build and are more trusted than // We set these _after_ loading from disk - because they come from the build and are more trusted than
// what is stored in flash // what is stored in flash
if (xstr(HW_VERSION)[0])
strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region)); strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region));
else
DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build flag
// Check for the old style of region code strings, if found, convert to the new enum.
// Those strings will look like "1.0-EU433"
if (radioConfig.preferences.region == RegionCode_Unset && strncmp(myNodeInfo.region, "1.0-", 4) == 0) {
const char *regionStr = myNodeInfo.region + 4; // EU433 or whatever
for (const RegionInfo *r = regions; r->code != RegionCode_Unset; r++)
if (strcmp(r->name, regionStr) == 0) {
radioConfig.preferences.region = r->code;
break;
}
}
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version)); strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
strncpy(myNodeInfo.hw_model, HW_VENDOR, sizeof(myNodeInfo.hw_model)); strncpy(myNodeInfo.hw_model, HW_VENDOR, sizeof(myNodeInfo.hw_model));
resetRadioConfig(); // If bogus settings got saved, then fix them resetRadioConfig(); // If bogus settings got saved, then fix them
DEBUG_MSG("NODENUM=0x%x, dbsize=%d\n", myNodeInfo.my_node_num, *numNodes); DEBUG_MSG("legacy_region=%s, region=%d, NODENUM=0x%x, dbsize=%d\n", myNodeInfo.region, radioConfig.preferences.region,
myNodeInfo.my_node_num, *numNodes);
} }
// We reserve a few nodenums for future use // We reserve a few nodenums for future use

View File

@ -46,8 +46,13 @@ class NodeDB
/// write to flash /// write to flash
void saveToDisk(); void saveToDisk();
// Reinit radio config if needed, because sometimes a buggy android app might send us bogus settings /** Reinit radio config if needed, because either:
void resetRadioConfig(); * a) sometimes a buggy android app might send us bogus settings or
* b) the client set factory_reset
*
* @return true if the config was completely reset, in that case, we should send it back to the client
*/
bool resetRadioConfig();
/// given a subpacket sniffed from the network, update our DB state /// given a subpacket sniffed from the network, update our DB state
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw /// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw

View File

@ -243,7 +243,10 @@ void PhoneAPI::handleSetRadio(const RadioConfig &r)
{ {
radioConfig = r; radioConfig = r;
service.reloadConfig(); bool didReset = service.reloadConfig();
if (didReset) {
state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client
}
} }
/** /**

View File

@ -10,6 +10,24 @@
#include <pb_decode.h> #include <pb_decode.h>
#include <pb_encode.h> #include <pb_encode.h>
#define RDEF(name, freq, spacing, num_ch, power_limit) \
{ \
RegionCode_##name, num_ch, power_limit, freq, spacing, #name \
}
const RegionInfo regions[] = {
RDEF(US, 903.08f, 2.16f, 13, 0), RDEF(EU433, 433.175f, 0.2f, 8, 0), RDEF(EU865, 865.2f, 0.3f, 10, 0),
RDEF(CN, 470.0f, 2.0f, 20, 0),
RDEF(JP, 920.0f, 0.5f, 10, 13), // See https://github.com/meshtastic/Meshtastic-device/issues/346 power level 13
RDEF(ANZ, 916.0f, 0.5f, 20, 0), // AU/NZ channel settings 915-928MHz
RDEF(KR, 921.9f, 0.2f, 8, 0), // KR channel settings (KR920-923) Start from TTN download channel
// freq. (921.9f is for download, others are for uplink)
RDEF(TW, 923.0f, 0.2f, 10, 0), // TW channel settings (AS2 bandplan 923-925MHz)
RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last
};
static const RegionInfo *myRegion;
/** /**
* ## LoRaWAN for North America * ## LoRaWAN for North America
@ -77,7 +95,15 @@ RadioInterface::RadioInterface()
{ {
assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
myNodeInfo.num_channels = NUM_CHANNELS; if (!myRegion) {
const RegionInfo *r = regions;
for (; r->code != RegionCode_Unset && r->code != radioConfig.preferences.region; r++)
;
myRegion = r;
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
myNodeInfo.num_channels = myRegion->numChannels; // Tell our android app how many channels we have
}
// Can't print strings this early - serial not setup yet // Can't print strings this early - serial not setup yet
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name); // DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
@ -127,9 +153,12 @@ void RadioInterface::applyModemConfig()
power = channelSettings.tx_power; power = channelSettings.tx_power;
assert(myRegion); // Should have been found in init
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name // If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
int channel_num = (channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelSettings.name)) % NUM_CHANNELS; int channel_num =
freq = CH0 + CH_SPACING * channel_num; (channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelSettings.name)) % myRegion->numChannels;
freq = myRegion->freq + myRegion->spacing * channel_num;
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelSettings.name, channelSettings.modem_config, channel_num, DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelSettings.name, channelSettings.modem_config, channel_num,
power); power);
@ -143,9 +172,9 @@ void RadioInterface::limitPower()
{ {
uint8_t maxPower = 255; // No limit uint8_t maxPower = 255; // No limit
#ifdef HW_VERSION_JP if (myRegion->powerLimit)
maxPower = 13; // See https://github.com/meshtastic/Meshtastic-device/issues/346 maxPower = myRegion->powerLimit;
#endif
if (power > maxPower) { if (power > maxPower) {
DEBUG_MSG("Lowering transmit power because of regulatory limits\n"); DEBUG_MSG("Lowering transmit power because of regulatory limits\n");
power = maxPower; power = maxPower;

View File

@ -59,3 +59,4 @@ PB_BIND(ManufacturingData, ManufacturingData, AUTO)

View File

@ -25,6 +25,18 @@ typedef enum _Constants {
Constants_Unused = 0 Constants_Unused = 0
} Constants; } Constants;
typedef enum _RegionCode {
RegionCode_Unset = 0,
RegionCode_US = 1,
RegionCode_EU433 = 2,
RegionCode_EU865 = 3,
RegionCode_CN = 4,
RegionCode_JP = 5,
RegionCode_ANZ = 6,
RegionCode_KR = 7,
RegionCode_TW = 8
} RegionCode;
typedef enum _Data_Type { typedef enum _Data_Type {
Data_Type_OPAQUE = 0, Data_Type_OPAQUE = 0,
Data_Type_CLEAR_TEXT = 1, Data_Type_CLEAR_TEXT = 1,
@ -108,6 +120,8 @@ typedef struct _RadioConfig_UserPreferences {
char wifi_ssid[33]; char wifi_ssid[33];
char wifi_password[64]; char wifi_password[64];
bool wifi_ap_mode; bool wifi_ap_mode;
RegionCode region;
bool factory_reset;
pb_size_t ignore_incoming_count; pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3]; uint32_t ignore_incoming[3];
} RadioConfig_UserPreferences; } RadioConfig_UserPreferences;
@ -230,6 +244,10 @@ typedef struct _ToRadio {
#define _Constants_MAX Constants_Unused #define _Constants_MAX Constants_Unused
#define _Constants_ARRAYSIZE ((Constants)(Constants_Unused+1)) #define _Constants_ARRAYSIZE ((Constants)(Constants_Unused+1))
#define _RegionCode_MIN RegionCode_Unset
#define _RegionCode_MAX RegionCode_TW
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1))
#define _Data_Type_MIN Data_Type_OPAQUE #define _Data_Type_MIN Data_Type_OPAQUE
#define _Data_Type_MAX Data_Type_CLEAR_READACK #define _Data_Type_MAX Data_Type_CLEAR_READACK
#define _Data_Type_ARRAYSIZE ((Data_Type)(Data_Type_CLEAR_READACK+1)) #define _Data_Type_ARRAYSIZE ((Data_Type)(Data_Type_CLEAR_READACK+1))
@ -248,7 +266,7 @@ typedef struct _ToRadio {
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0} #define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0}
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, {0, 0, 0}} #define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, 0, 0, {0, 0, 0}}
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0} #define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
@ -264,7 +282,7 @@ typedef struct _ToRadio {
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0} #define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, {0, 0, 0}} #define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, 0, 0, {0, 0, 0}}
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0} #define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
@ -322,7 +340,9 @@ typedef struct _ToRadio {
#define RadioConfig_UserPreferences_wifi_ssid_tag 12 #define RadioConfig_UserPreferences_wifi_ssid_tag 12
#define RadioConfig_UserPreferences_wifi_password_tag 13 #define RadioConfig_UserPreferences_wifi_password_tag 13
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14 #define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
#define RadioConfig_UserPreferences_ignore_incoming_tag 102 #define RadioConfig_UserPreferences_region_tag 15
#define RadioConfig_UserPreferences_factory_reset_tag 100
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
#define RouteDiscovery_route_tag 2 #define RouteDiscovery_route_tag 2
#define User_id_tag 1 #define User_id_tag 1
#define User_long_name_tag 2 #define User_long_name_tag 2
@ -477,7 +497,9 @@ X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 11) \
X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \ X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \
X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \ X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \ X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 102) X(a, STATIC, SINGULAR, UENUM, region, 15) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
#define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_CALLBACK NULL
#define RadioConfig_UserPreferences_DEFAULT NULL #define RadioConfig_UserPreferences_DEFAULT NULL
@ -613,11 +635,11 @@ extern const pb_msgdesc_t ManufacturingData_msg;
#define SubPacket_size 274 #define SubPacket_size 274
#define MeshPacket_size 313 #define MeshPacket_size 313
#define ChannelSettings_size 84 #define ChannelSettings_size 84
#define RadioConfig_size 277 #define RadioConfig_size 282
#define RadioConfig_UserPreferences_size 188 #define RadioConfig_UserPreferences_size 193
#define NodeInfo_size 132 #define NodeInfo_size 132
#define MyNodeInfo_size 110 #define MyNodeInfo_size 110
#define DeviceState_size 5429 #define DeviceState_size 5434
#define DebugString_size 258 #define DebugString_size 258
#define FromRadio_size 322 #define FromRadio_size 322
#define ToRadio_size 316 #define ToRadio_size 316

View File

@ -0,0 +1 @@
../nrf52/wifi-stubs.cpp