diff --git a/docs/software/TODO.md b/docs/software/TODO.md
index 2633d3bcf..5c09e9b54 100644
--- a/docs/software/TODO.md
+++ b/docs/software/TODO.md
@@ -4,11 +4,19 @@ You probably don't care about this section - skip to the next one.
## before next release
+* DONE have android fill in if local GPS has poor signal
+* fix heltec battery scaling
+* add reference counting to mesh packets
+* allow multiple simultanteous phoneapi connections
+* DONE split position.time and last_heard
+* DONE update android app to use last_heard
+* DONE turn off bluetooth interface ENTIRELY while using serial API (was python client times out on connect sometimes)
+* DONE gps assistance from phone not working?
* DONE test latest firmware update with is_router
* DONE firmware OTA updates of is_router true nodes fails?
* DONE add UI in android app to reset to defaults https://github.com/meshtastic/Meshtastic-Android/issues/263
* DONE TEST THIS! changing channels requires a reboot to take effect https://github.com/meshtastic/Meshtastic-device/issues/752
-* DIBE bug report with remote info request timing out
+* DONE bug report with remote info request timing out
* DONE retest channel changing in android (using sim?)
* DONE move remote admin doc from forum into git
* DONE check crashlytics
diff --git a/proto b/proto
index 820fa497d..0ea232802 160000
--- a/proto
+++ b/proto
@@ -1 +1 @@
-Subproject commit 820fa497dfde07e129cad6955bf2f4b2b9cecebc
+Subproject commit 0ea232802651fd6aaa53c93c09f4c2eb36470dd0
diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp
index 86bc91639..338412c3d 100644
--- a/src/PowerFSM.cpp
+++ b/src/PowerFSM.cpp
@@ -9,6 +9,23 @@
#include "sleep.h"
#include "target_specific.h"
+/// Should we behave as if we have AC power now?
+static bool isPowered()
+{
+ bool isRouter = radioConfig.preferences.is_router;
+
+ // If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
+ // We assume routers might be powered all the time, but from a low current (solar) source
+ bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
+
+ /* To determine if we're externally powered, assumptions
+ 1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
+
+ 2) If we detect USB power from the power management chip, we must be getting power externally.
+ */
+ return !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
+}
+
static void sdsEnter()
{
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
@@ -119,14 +136,34 @@ static void serialEnter()
{
setBluetoothEnable(false);
screen->setOn(true);
- screen->print("Using API...\n");
+ screen->print("Serial connected\n");
+}
+
+static void serialExit()
+{
+ screen->print("Serial disconnected\n");
}
static void powerEnter()
{
- screen->setOn(true);
- setBluetoothEnable(true);
- screen->print("Powered...\n");
+ if (!isPowered()) {
+ // If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
+ DEBUG_MSG("Loss of power in Powered\n");
+ powerFSM.trigger(EVENT_POWER_DISCONNECTED);
+ } else {
+ screen->setOn(true);
+ setBluetoothEnable(true);
+ screen->print("Powered...\n");
+ }
+}
+
+static void powerIdle()
+{
+ if (!isPowered()) {
+ // If we got here, we are in the wrong state
+ DEBUG_MSG("Loss of power in Powered\n");
+ powerFSM.trigger(EVENT_POWER_DISCONNECTED);
+ }
}
static void powerExit()
@@ -153,6 +190,14 @@ static void onEnter()
}
}
+static void onIdle()
+{
+ if (isPowered()) {
+ // If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
+ powerFSM.trigger(EVENT_POWER_CONNECTED);
+ }
+}
+
static void screenPress()
{
screen->onPress();
@@ -164,26 +209,16 @@ State stateSDS(sdsEnter, NULL, NULL, "SDS");
State stateLS(lsEnter, lsIdle, lsExit, "LS");
State stateNB(nbEnter, NULL, NULL, "NB");
State stateDARK(darkEnter, NULL, NULL, "DARK");
-State stateSERIAL(serialEnter, NULL, NULL, "SERIAL");
+State stateSERIAL(serialEnter, NULL, serialExit, "SERIAL");
State stateBOOT(bootEnter, NULL, NULL, "BOOT");
-State stateON(onEnter, NULL, NULL, "ON");
-State statePOWER(powerEnter, NULL, powerExit, "POWER");
+State stateON(onEnter, onIdle, NULL, "ON");
+State statePOWER(powerEnter, powerIdle, powerExit, "POWER");
Fsm powerFSM(&stateBOOT);
void PowerFSM_setup()
{
bool isRouter = radioConfig.preferences.is_router;
-
- // If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
- // We assume routers might be powered all the time, but from a low current (solar) source
- bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
-
- /* To determine if we're externally powered, assumptions
- 1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
-
- 2) If we detect USB power from the power management chip, we must be getting power externally.
- */
- bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
+ bool hasPower = isPowered();
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
@@ -231,22 +266,25 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
}
+ // If we are not in statePOWER but get a serial connection, suppress sleep (and keep the screen on) while connected
powerFSM.add_transition(&stateLS, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
powerFSM.add_transition(&stateNB, &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(&statePOWER, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
- if (!isLowPower) {
- 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");
- }
+ // If we get power connected, go to the power connect state
+ 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, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
- powerFSM.add_transition(&stateSERIAL, &stateNB, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect");
+ // the only way to leave state serial is for the client to disconnect (or we timeout and force disconnect them)
+ // when we leave, go to ON (which might not be the correct state if we have power connected, we will fix that in onEnter)
+ powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect");
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp
index ad1cf642a..137fbcf0d 100644
--- a/src/SerialConsole.cpp
+++ b/src/SerialConsole.cpp
@@ -6,27 +6,29 @@
#define Port Serial
-SerialConsole console;
+SerialConsole *console;
+
+void consoleInit()
+{
+ new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
+}
void consolePrintf(const char *format, ...)
{
va_list arg;
va_start(arg, format);
- console.vprintf(format, arg);
+ console->vprintf(format, arg);
va_end(arg);
}
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
{
+ assert(!console);
+ console = this;
canWrite = false; // We don't send packets to our port until it has talked to us first
- // setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
-}
+ // setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
-/// Do late init that can't happen at constructor time
-void SerialConsole::init()
-{
Port.begin(SERIAL_BAUD);
- StreamAPI::init();
emitRebooted();
}
@@ -34,14 +36,14 @@ void SerialConsole::init()
* we override this to notice when we've received a protobuf over the serial
* stream. Then we shunt off debug serial output.
*/
-void SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
+bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
{
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
if (!radioConfig.preferences.debug_log_enabled)
setDestination(&noopPrint);
canWrite = true;
- StreamAPI::handleToRadio(buf, len);
+ return StreamAPI::handleToRadio(buf, len);
}
/// Hookable to find out when connection changes
diff --git a/src/SerialConsole.h b/src/SerialConsole.h
index b4f076286..b057c1931 100644
--- a/src/SerialConsole.h
+++ b/src/SerialConsole.h
@@ -11,14 +11,11 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
public:
SerialConsole();
- /// Do late init that can't happen at constructor time
- virtual void init();
-
/**
* we override this to notice when we've received a protobuf over the serial stream. Then we shunt off
* debug serial output.
*/
- virtual void handleToRadio(const uint8_t *buf, size_t len);
+ virtual bool handleToRadio(const uint8_t *buf, size_t len);
virtual size_t write(uint8_t c)
{
@@ -34,5 +31,6 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
// A simple wrapper to allow non class aware code write to the console
void consolePrintf(const char *format, ...);
+void consoleInit();
-extern SerialConsole console;
+extern SerialConsole *console;
diff --git a/src/concurrency/BinarySemaphoreFreeRTOS.h b/src/concurrency/BinarySemaphoreFreeRTOS.h
index b5e488fd2..2883151d8 100644
--- a/src/concurrency/BinarySemaphoreFreeRTOS.h
+++ b/src/concurrency/BinarySemaphoreFreeRTOS.h
@@ -1,6 +1,5 @@
#pragma once
-#include "configuration.h"
#include "../freertosinc.h"
namespace concurrency
@@ -28,4 +27,4 @@ class BinarySemaphoreFreeRTOS
#endif
-}
\ No newline at end of file
+} // namespace concurrency
\ No newline at end of file
diff --git a/src/configuration.h b/src/configuration.h
index 1704ad14a..f0d3a0a53 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -457,7 +457,7 @@ along with this program. If not, see .
#include "SerialConsole.h"
-#define DEBUG_PORT console // Serial debug port
+#define DEBUG_PORT (*console) // Serial debug port
// What platforms should use SEGGER?
#ifdef NRF52_SERIES
diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp
index 843b14cf6..870d20ffd 100644
--- a/src/esp32/BluetoothSoftwareUpdate.cpp
+++ b/src/esp32/BluetoothSoftwareUpdate.cpp
@@ -16,7 +16,6 @@
int16_t updateResultHandle = -1;
static CRC32 crc;
-static uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
static uint32_t updateExpectedSize, updateActualSize;
static uint8_t update_result;
@@ -139,14 +138,6 @@ int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct bl
return chr_readwrite8(&update_region, sizeof(update_region), ctxt);
}
-void bluetoothRebootCheck()
-{
- if (rebootAtMsec && millis() > rebootAtMsec) {
- DEBUG_MSG("Rebooting for update\n");
- ESP.restart();
- }
-}
-
/*
See bluetooth-api.md
diff --git a/src/esp32/BluetoothSoftwareUpdate.h b/src/esp32/BluetoothSoftwareUpdate.h
index f5e1a1ded..478d478d5 100644
--- a/src/esp32/BluetoothSoftwareUpdate.h
+++ b/src/esp32/BluetoothSoftwareUpdate.h
@@ -4,8 +4,6 @@
void reinitUpdateService();
-void bluetoothRebootCheck();
-
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/src/esp32/main-esp32.cpp b/src/esp32/main-esp32.cpp
index ebe5477b5..e000ad5af 100644
--- a/src/esp32/main-esp32.cpp
+++ b/src/esp32/main-esp32.cpp
@@ -97,7 +97,6 @@ void esp32Loop()
{
esp_task_wdt_reset(); // service our app level watchdog
loopBLE();
- bluetoothRebootCheck();
// for debug printing
// radio.radioIf.canSleep();
diff --git a/src/main.cpp b/src/main.cpp
index 6a4caf330..7ce86ffc0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -177,6 +177,7 @@ class ButtonThread : public OSThread
OneButton userButtonAlt;
#endif
static bool shutdown_on_long_stop;
+
public:
static uint32_t longPressTime;
@@ -250,15 +251,15 @@ class ButtonThread : public OSThread
power->shutdown();
}
#elif NRF52_SERIES
- // Do actual shutdown when button released, otherwise the button release
- // may wake the board immediatedly.
- if (!shutdown_on_long_stop) {
- DEBUG_MSG("Shutdown from long press");
- playBeep();
- ledOff(PIN_LED1);
- ledOff(PIN_LED2);
- shutdown_on_long_stop = true;
- }
+ // Do actual shutdown when button released, otherwise the button release
+ // may wake the board immediatedly.
+ if (!shutdown_on_long_stop) {
+ DEBUG_MSG("Shutdown from long press");
+ playBeep();
+ ledOff(PIN_LED1);
+ ledOff(PIN_LED2);
+ shutdown_on_long_stop = true;
+ }
#endif
} else {
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
@@ -315,9 +316,8 @@ void setup()
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
#endif
-// Debug
#ifdef DEBUG_PORT
- DEBUG_PORT.init(); // Set serial baud rate and init our mesh console
+ consoleInit(); // Set serial baud rate and init our mesh console
#endif
initDeepSleep();
@@ -576,14 +576,24 @@ Periodic axpDebugOutput(axpDebugRead);
axpDebugOutput.setup();
#endif
+uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
+
+void rebootCheck()
+{
+ if (rebootAtMsec && millis() > rebootAtMsec) {
+#ifndef NO_ESP32
+ DEBUG_MSG("Rebooting for update\n");
+ ESP.restart();
+#else
+ DEBUG_MSG("FIXME implement reboot for this platform");
+#endif
+ }
+}
+
void loop()
{
// axpDebugOutput.loop();
-#ifdef DEBUG_PORT
- DEBUG_PORT.loop(); // Send/receive protobufs over the serial port
-#endif
-
// heap_caps_check_integrity_all(true); // FIXME - disable this expensive check
#ifndef NO_ESP32
@@ -592,6 +602,7 @@ void loop()
#ifdef NRF52_SERIES
nrf52Loop();
#endif
+ rebootCheck();
// For debugging
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
diff --git a/src/main.h b/src/main.h
index edb50d0d7..1a6dfe439 100644
--- a/src/main.h
+++ b/src/main.h
@@ -20,4 +20,6 @@ extern graphics::Screen *screen;
// Return a human readable string of the form "Meshtastic_ab13"
const char *getDeviceName();
+extern uint32_t rebootAtMsec;
+
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop();
diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp
index d542b21cf..4a42f7716 100644
--- a/src/mesh/MeshService.cpp
+++ b/src/mesh/MeshService.cpp
@@ -114,7 +114,7 @@ bool MeshService::reloadConfig()
void MeshService::reloadOwner()
{
assert(nodeInfoPlugin);
- if(nodeInfoPlugin)
+ if (nodeInfoPlugin)
nodeInfoPlugin->sendOurNodeInfo();
nodeDB.saveToDisk();
}
@@ -172,13 +172,12 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
assert(node);
if (node->has_position) {
- if(positionPlugin) {
+ if (positionPlugin) {
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
positionPlugin->sendOurPosition(dest, wantReplies);
}
- }
- else {
- if(nodeInfoPlugin) {
+ } else {
+ if (nodeInfoPlugin) {
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
}
@@ -198,10 +197,13 @@ NodeInfo *MeshService::refreshMyNodeInfo()
Position &position = node->position;
- // Update our local node info with our position (even if we don't decide to update anyone else)
- position.time =
+ // Update our local node info with our time (even if we don't decide to update anyone else)
+ node->last_heard =
getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
+ // For the time in the position field, only set that if we have a real GPS clock
+ position.time = getValidTime(RTCQualityGPS);
+
position.battery_level = powerStatus->getBatteryChargePercent();
updateBatteryLevel(position.battery_level);
diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h
index 0f2e772b3..7d22a3004 100644
--- a/src/mesh/MeshService.h
+++ b/src/mesh/MeshService.h
@@ -84,13 +84,12 @@ class MeshService
NodeInfo *refreshMyNodeInfo();
private:
-
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
/// returns 0 to allow futher processing
int onGPSChanged(const meshtastic::GPSStatus *arg);
- /// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it needs
- /// to keep the packet around it makes a copy
+ /// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
+ /// needs to keep the packet around it makes a copy
int handleFromRadio(const MeshPacket *p);
friend class RoutingPlugin;
};
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 1600cec65..a6ce8e4c8 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -419,8 +419,7 @@ uint32_t sinceLastSeen(const NodeInfo *n)
{
uint32_t now = getTime();
- uint32_t last_seen = n->position.time;
- int delta = (int)(now - last_seen);
+ int delta = (int)(now - n->last_heard);
if (delta < 0) // our clock must be slightly off still - not set from GPS yet
delta = 0;
@@ -454,7 +453,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p)
// Be careful to only update fields that have been set by the sender
// A lot of position reports don't have time populated. In that case, be careful to not blow away the time we
// recorded based on the packet rxTime
- if (!info->position.time && p.time)
+ if (p.time)
info->position.time = p.time;
if (p.battery_level)
info->position.battery_level = p.battery_level;
@@ -504,11 +503,8 @@ void NodeDB::updateFrom(const MeshPacket &mp)
NodeInfo *info = getOrCreateNode(getFrom(&mp));
- if (mp.rx_time) { // if the packet has a valid timestamp use it to update our last_seen
-
- info->has_position = true; // at least the time is valid
- info->position.time = mp.rx_time;
- }
+ if (mp.rx_time) // if the packet has a valid timestamp use it to update our last_heard
+ info->last_heard = mp.rx_time;
if (mp.rx_snr)
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index b50381e70..db039afb2 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -1,10 +1,10 @@
#include "PhoneAPI.h"
+#include "Channels.h"
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "RadioInterface.h"
-#include "Channels.h"
#include
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
@@ -17,66 +17,73 @@
PhoneAPI::PhoneAPI() {}
-void PhoneAPI::init()
+PhoneAPI::~PhoneAPI()
{
- observe(&service.fromNumChanged);
-}
-
-PhoneAPI::~PhoneAPI() {
close();
}
-void PhoneAPI::close() {
- unobserve();
- state = STATE_SEND_NOTHING;
- bool oldConnected = isConnected;
- isConnected = false;
- if(oldConnected != isConnected)
- onConnectionChanged(isConnected);
+void PhoneAPI::handleStartConfig()
+{
+ if (!isConnected()) {
+ onConnectionChanged(true);
+ observe(&service.fromNumChanged);
+ }
+
+ // even if we were already connected - restart our state machine
+ state = STATE_SEND_MY_INFO;
+
+ DEBUG_MSG("Reset nodeinfo read pointer\n");
+ nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
+ nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
+ // this will break once we have multiple instances of PhoneAPI running independently
+}
+
+void PhoneAPI::close()
+{
+ if (state != STATE_SEND_NOTHING) {
+ state = STATE_SEND_NOTHING;
+
+ unobserve();
+ releasePhonePacket(); // Don't leak phone packets on shutdown
+
+ onConnectionChanged(false);
+ }
}
void PhoneAPI::checkConnectionTimeout()
{
- if (isConnected) {
+ if (isConnected()) {
bool newConnected = (millis() - lastContactMsec < getPref_phone_timeout_secs() * 1000L);
- if (!newConnected) {
- isConnected = false;
- onConnectionChanged(isConnected);
- }
+ if (!newConnected)
+ close();
}
}
/**
* Handle a ToRadio protobuf
*/
-void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
+bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
{
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep
lastContactMsec = millis();
- if (!isConnected) {
- isConnected = true;
- onConnectionChanged(isConnected);
- }
+
// return (lastContactMsec != 0) &&
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
switch (toRadioScratch.which_payloadVariant) {
- case ToRadio_packet_tag: {
- MeshPacket &p = toRadioScratch.packet;
- printPacket("PACKET FROM PHONE", &p);
- service.handleToRadio(p);
- break;
- }
+ case ToRadio_packet_tag:
+ return handleToRadioPacket(toRadioScratch.packet);
+
case ToRadio_want_config_id_tag:
config_nonce = toRadioScratch.want_config_id;
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
- state = STATE_SEND_MY_INFO;
- DEBUG_MSG("Reset nodeinfo read pointer\n");
- nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
- nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
- // this will break once we have multiple instances of PhoneAPI running independently
+ handleStartConfig();
+ break;
+
+ case ToRadio_disconnect_tag:
+ close();
break;
default:
@@ -86,6 +93,8 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
} else {
DEBUG_MSG("Error: ignoring malformed toradio\n");
}
+
+ return false;
}
/**
@@ -120,14 +129,12 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
case STATE_SEND_MY_INFO:
// If the user has specified they don't want our node to share its location, make sure to tell the phone
// app not to send locations on our behalf.
- myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled)
- ? true
- : (gps && gps->isConnected()); // Update with latest GPS connect info
+ myNodeInfo.has_gps = gps && gps->isConnected(); // Update with latest GPS connect info
fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag;
fromRadioScratch.my_info = myNodeInfo;
state = STATE_SEND_NODEINFO;
- service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
+ service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
break;
case STATE_SEND_NODEINFO: {
@@ -135,7 +142,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time
if (info) {
- DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id,
+ DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->last_heard, info->user.id,
info->user.long_name);
fromRadioScratch.which_payloadVariant = FromRadio_node_info_tag;
fromRadioScratch.node_info = *info;
@@ -159,16 +166,13 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
case STATE_SEND_PACKETS:
// Do we have a message from the mesh?
if (packetForPhone) {
-
printPacket("phone downloaded packet", packetForPhone);
// Encapsulate as a FromRadio packet
fromRadioScratch.which_payloadVariant = FromRadio_packet_tag;
fromRadioScratch.packet = *packetForPhone;
-
- service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
- packetForPhone = NULL;
}
+ releasePhonePacket();
break;
default:
@@ -187,6 +191,16 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
return 0;
}
+void PhoneAPI::handleDisconnect() {}
+
+void PhoneAPI::releasePhonePacket()
+{
+ if (packetForPhone) {
+ service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
+ packetForPhone = NULL;
+ }
+}
+
/**
* Return true if we have data available to send to the phone
*/
@@ -226,7 +240,13 @@ bool PhoneAPI::available()
/**
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
*/
-void PhoneAPI::handleToRadioPacket(MeshPacket *p) {}
+bool PhoneAPI::handleToRadioPacket(MeshPacket &p)
+{
+ printPacket("PACKET FROM PHONE", &p);
+ service.handleToRadio(p);
+
+ return true;
+}
/// If the mesh service tells us fromNum has changed, tell the phone
int PhoneAPI::onNotify(uint32_t newValue)
diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h
index 6d03d2c80..02165aae3 100644
--- a/src/mesh/PhoneAPI.h
+++ b/src/mesh/PhoneAPI.h
@@ -22,6 +22,7 @@ class PhoneAPI
enum State {
STATE_UNUSED, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API
STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config
+ // (disconnected)
STATE_SEND_MY_INFO, // send our my info record
// STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet
// STATE_SEND_OWNER, no need to send Owner specially, it is just part of the nodedb
@@ -58,17 +59,15 @@ class PhoneAPI
/// Destructor - calls close()
virtual ~PhoneAPI();
- /// Do late init that can't happen at constructor time
- virtual void init();
-
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
virtual void close();
/**
* Handle a ToRadio protobuf
+ * @return true true if a packet was queued for sending (so that caller can yield)
*/
- virtual void handleToRadio(const uint8_t *buf, size_t len);
+ virtual bool handleToRadio(const uint8_t *buf, size_t len);
/**
* Get the next packet we want to send to the phone
@@ -83,17 +82,16 @@ class PhoneAPI
*/
bool available();
- protected:
- /// Are we currently connected to a client?
- bool isConnected = false;
+ bool isConnected() { return state != STATE_SEND_NOTHING; }
+ protected:
/// Our fromradio packet while it is being assembled
FromRadio fromRadioScratch;
/// Hookable to find out when connection changes
virtual void onConnectionChanged(bool connected) {}
- /// If we haven't heard from the other side in a while then say not connected
+ /// If we haven't heard from the other side in a while then say not connected
void checkConnectionTimeout();
/**
@@ -101,11 +99,22 @@ class PhoneAPI
*/
virtual void onNowHasData(uint32_t fromRadioNum) {}
- private:
/**
- * Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
+ * Subclasses can use this to find out when a client drops the link
*/
- void handleToRadioPacket(MeshPacket *p);
+ virtual void handleDisconnect();
+
+ private:
+ void releasePhonePacket();
+
+ /// begin a new connection
+ void handleStartConfig();
+
+ /**
+ * Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it
+ * @return true true if a packet was queued for sending
+ */
+ bool handleToRadioPacket(MeshPacket &p);
/// If the mesh service tells us fromNum has changed, tell the phone
virtual int onNotify(uint32_t newValue);
diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp
index a5e36d463..2bc82b084 100644
--- a/src/mesh/StreamAPI.cpp
+++ b/src/mesh/StreamAPI.cpp
@@ -5,48 +5,62 @@
#define START2 0xc3
#define HEADER_LEN 4
-void StreamAPI::loop()
+int32_t StreamAPI::runOnce()
{
+ auto result = readStream();
writeStream();
- readStream();
checkConnectionTimeout();
+ return result;
}
/**
* Read any rx chars from the link and call handleToRadio
*/
-void StreamAPI::readStream()
+int32_t StreamAPI::readStream()
{
- while (stream->available()) { // Currently we never want to block
- uint8_t c = stream->read();
+ uint32_t now = millis();
+ if (!stream->available()) {
+ // Nothing available this time, if the computer has talked to us recently, poll often, otherwise let CPU sleep a long time
+ bool recentRx = (now - lastRxMsec) < 2000;
+ return recentRx ? 5 : 250;
+ } else {
+ while (stream->available()) { // Currently we never want to block
+ uint8_t c = stream->read();
- // Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
- size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
+ // Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
+ size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
- rxBuf[ptr] = c; // store all bytes (including framing)
+ rxBuf[ptr] = c; // store all bytes (including framing)
- if (ptr == 0) { // looking for START1
- if (c != START1)
- rxPtr = 0; // failed to find framing
- } else if (ptr == 1) { // looking for START2
- if (c != START2)
- rxPtr = 0; // failed to find framing
- } else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
- uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
+ if (ptr == 0) { // looking for START1
+ if (c != START1)
+ rxPtr = 0; // failed to find framing
+ } else if (ptr == 1) { // looking for START2
+ if (c != START2)
+ rxPtr = 0; // failed to find framing
+ } else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
+ uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
- if (ptr == HEADER_LEN) {
- // we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
- // protobuf also)
- if (len > MAX_TO_FROM_RADIO_SIZE)
- rxPtr = 0; // length is bogus, restart search for framing
- }
+ if (ptr == HEADER_LEN) {
+ // we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
+ // protobuf also)
+ if (len > MAX_TO_FROM_RADIO_SIZE)
+ rxPtr = 0; // length is bogus, restart search for framing
+ }
- if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
- // If we didn't just fail the packet and we now have the right # of bytes, parse it
- handleToRadio(rxBuf + HEADER_LEN, len);
- rxPtr = 0; // start over again
+ if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
+ rxPtr = 0; // start over again on the next packet
+
+ // If we didn't just fail the packet and we now have the right # of bytes, parse it
+ if (handleToRadio(rxBuf + HEADER_LEN, len))
+ return 0; // we want to be called again ASAP because we still have more work to do
+ }
}
}
+
+ // we had packets available this time, so assume we might have them next time also
+ lastRxMsec = now;
+ return 0;
}
}
@@ -71,7 +85,7 @@ void StreamAPI::writeStream()
void StreamAPI::emitTxBuffer(size_t len)
{
if (len != 0) {
- DEBUG_MSG("emit tx %d\n", len);
+ // DEBUG_MSG("emit tx %d\n", len);
txBuf[0] = START1;
txBuf[1] = START2;
txBuf[2] = (len >> 8) & 0xff;
@@ -93,6 +107,6 @@ void StreamAPI::emitRebooted()
fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag;
fromRadioScratch.rebooted = true;
- DEBUG_MSG("Emitting reboot packet for serial shell\n");
+ // DEBUG_MSG("Emitting reboot packet for serial shell\n");
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
}
\ No newline at end of file
diff --git a/src/mesh/StreamAPI.h b/src/mesh/StreamAPI.h
index ed0a5fbd4..6180a95d8 100644
--- a/src/mesh/StreamAPI.h
+++ b/src/mesh/StreamAPI.h
@@ -2,6 +2,7 @@
#include "PhoneAPI.h"
#include "Stream.h"
+#include "concurrency/OSThread.h"
// A To/FromRadio packet + our 32 bit header
#define MAX_STREAM_BUF_SIZE (MAX_TO_FROM_RADIO_SIZE + sizeof(uint32_t))
@@ -27,7 +28,7 @@ valid utf8 encoding. This makes it a bit easier to start a device outputting reg
after it has received a valid packet from the PC, turn off unencoded debug printing and switch to this packet encoding.
*/
-class StreamAPI : public PhoneAPI
+class StreamAPI : public PhoneAPI, protected concurrency::OSThread
{
/**
* The stream we read/write from
@@ -37,21 +38,23 @@ class StreamAPI : public PhoneAPI
uint8_t rxBuf[MAX_STREAM_BUF_SIZE];
size_t rxPtr = 0;
+ /// time of last rx, used, to slow down our polling if we haven't heard from anyone
+ uint32_t lastRxMsec = 0;
+
public:
- StreamAPI(Stream *_stream) : stream(_stream) {}
+ StreamAPI(Stream *_stream) : concurrency::OSThread("StreamAPI"), stream(_stream) {}
/**
* Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the
* phone.
- * FIXME, to support better power behavior instead move to a thread and block on serial reads.
*/
- void loop();
+ virtual int32_t runOnce();
private:
/**
* Read any rx chars from the link and call handleToRadio
*/
- void readStream();
+ int32_t readStream();
/**
* call getFromRadio() and deliver encapsulated packets to the Stream
@@ -63,7 +66,7 @@ class StreamAPI : public PhoneAPI
* Send a FromRadio.rebooted = true packet to the phone
*/
void emitRebooted();
-
+
/**
* Send the current txBuffer over our stream
*/
diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h
index cf71a9cb2..a2e753546 100644
--- a/src/mesh/generated/admin.pb.h
+++ b/src/mesh/generated/admin.pb.h
@@ -26,6 +26,7 @@ typedef struct _AdminMessage {
bool confirm_set_channel;
bool confirm_set_radio;
bool exit_simulator;
+ int32_t reboot_seconds;
};
} AdminMessage;
@@ -49,6 +50,7 @@ extern "C" {
#define AdminMessage_confirm_set_channel_tag 32
#define AdminMessage_confirm_set_radio_tag 33
#define AdminMessage_exit_simulator_tag 34
+#define AdminMessage_reboot_seconds_tag 35
/* Struct field encoding specification for nanopb */
#define AdminMessage_FIELDLIST(X, a) \
@@ -61,7 +63,8 @@ X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_requ
X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7) \
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_channel,confirm_set_channel), 32) \
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) \
-X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34)
+X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34) \
+X(a, STATIC, ONEOF, INT32, (variant,reboot_seconds,reboot_seconds), 35)
#define AdminMessage_CALLBACK NULL
#define AdminMessage_DEFAULT NULL
#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig
diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h
index 55bf6ce13..fa5de7b93 100644
--- a/src/mesh/generated/deviceonly.pb.h
+++ b/src/mesh/generated/deviceonly.pb.h
@@ -125,7 +125,7 @@ extern const pb_msgdesc_t ChannelFile_msg;
/* Maximum encoded size of messages (where known) */
#define LegacyRadioConfig_size 4
#define LegacyRadioConfig_LegacyPreferences_size 2
-#define DeviceState_size 4926
+#define DeviceState_size 5118
#define ChannelFile_size 832
#ifdef __cplusplus
diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h
index f9db4e6b9..4f30ade8b 100644
--- a/src/mesh/generated/mesh.pb.h
+++ b/src/mesh/generated/mesh.pb.h
@@ -162,6 +162,7 @@ typedef struct _NodeInfo {
User user;
bool has_position;
Position position;
+ uint32_t last_heard;
float snr;
} NodeInfo;
@@ -192,6 +193,7 @@ typedef struct _ToRadio {
union {
MeshPacket packet;
uint32_t want_config_id;
+ bool disconnect;
};
} ToRadio;
@@ -233,7 +235,7 @@ extern "C" {
#define Routing_init_default {0, {RouteDiscovery_init_default}}
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0}
-#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0}
+#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0}
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
#define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}}
@@ -244,7 +246,7 @@ extern "C" {
#define Routing_init_zero {0, {RouteDiscovery_init_zero}}
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0}
-#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0}
+#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0}
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
#define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}}
@@ -300,6 +302,7 @@ extern "C" {
#define NodeInfo_num_tag 1
#define NodeInfo_user_tag 2
#define NodeInfo_position_tag 3
+#define NodeInfo_last_heard_tag 4
#define NodeInfo_snr_tag 7
#define Routing_route_request_tag 1
#define Routing_route_reply_tag 2
@@ -313,6 +316,7 @@ extern "C" {
#define FromRadio_packet_tag 11
#define ToRadio_packet_tag 2
#define ToRadio_want_config_id_tag 100
+#define ToRadio_disconnect_tag 104
/* Struct field encoding specification for nanopb */
#define Position_FIELDLIST(X, a) \
@@ -378,6 +382,7 @@ X(a, STATIC, SINGULAR, INT32, rx_rssi, 13)
X(a, STATIC, SINGULAR, UINT32, num, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \
X(a, STATIC, OPTIONAL, MESSAGE, position, 3) \
+X(a, STATIC, SINGULAR, FIXED32, last_heard, 4) \
X(a, STATIC, SINGULAR, FLOAT, snr, 7)
#define NodeInfo_CALLBACK NULL
#define NodeInfo_DEFAULT NULL
@@ -426,7 +431,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 11)
#define ToRadio_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \
-X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100)
+X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) \
+X(a, STATIC, ONEOF, BOOL, (payloadVariant,disconnect,disconnect), 104)
#define ToRadio_CALLBACK NULL
#define ToRadio_DEFAULT NULL
#define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket
@@ -463,7 +469,7 @@ extern const pb_msgdesc_t ToRadio_msg;
#define Routing_size 42
#define Data_size 260
#define MeshPacket_size 309
-#define NodeInfo_size 126
+#define NodeInfo_size 131
#define MyNodeInfo_size 95
#define LogRecord_size 81
#define FromRadio_size 318
diff --git a/src/mesh/wifi/WiFiServerAPI.cpp b/src/mesh/wifi/WiFiServerAPI.cpp
index 37183975e..c0be8bc4a 100644
--- a/src/mesh/wifi/WiFiServerAPI.cpp
+++ b/src/mesh/wifi/WiFiServerAPI.cpp
@@ -40,18 +40,20 @@ void WiFiServerAPI::onConnectionChanged(bool connected)
}
/// override close to also shutdown the TCP link
-void WiFiServerAPI::close() {
+void WiFiServerAPI::close()
+{
client.stop(); // drop tcp connection
StreamAPI::close();
}
-bool WiFiServerAPI::loop()
+int32_t WiFiServerAPI::runOnce()
{
if (client.connected()) {
- StreamAPI::loop();
- return true;
+ return StreamAPI::runOnce();
} else {
- return false;
+ DEBUG_MSG("Client dropped connection, suspending API service\n");
+ enabled = false; // we no longer need to run
+ return 0;
}
}
@@ -78,18 +80,5 @@ int32_t WiFiServerPort::runOnce()
openAPI = new WiFiServerAPI(client);
}
- if (openAPI) {
- // Allow idle processing so the API can read from its incoming stream
- if(!openAPI->loop()) {
- // If our API link was up, shut it down
-
- DEBUG_MSG("Client dropped connection, closing API client\n");
- // Note: we can't call delete here because this object includes other state
- // besides the stream API. Instead kill it later when we start a new instance
- delete openAPI;
- openAPI = NULL;
- }
- return 0; // run fast while our API server is running
- } else
- return 100; // only check occasionally for incoming connections
+ return 100; // only check occasionally for incoming connections
}
\ No newline at end of file
diff --git a/src/mesh/wifi/WiFiServerAPI.h b/src/mesh/wifi/WiFiServerAPI.h
index 46e2fad93..96cfb2bb0 100644
--- a/src/mesh/wifi/WiFiServerAPI.h
+++ b/src/mesh/wifi/WiFiServerAPI.h
@@ -1,7 +1,6 @@
#pragma once
#include "StreamAPI.h"
-#include "concurrency/OSThread.h"
#include
/**
@@ -18,15 +17,14 @@ class WiFiServerAPI : public StreamAPI
virtual ~WiFiServerAPI();
- /// @return true if we want to keep running, or false if we are ready to be destroyed
- virtual bool loop(); // Check for dropped client connections
-
/// override close to also shutdown the TCP link
virtual void close();
protected:
/// Hookable to find out when connection changes
virtual void onConnectionChanged(bool connected);
+
+ virtual int32_t runOnce(); // Check for dropped client connections
};
/**
diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp
index 1416453b1..0618c73e6 100644
--- a/src/nimble/BluetoothUtil.cpp
+++ b/src/nimble/BluetoothUtil.cpp
@@ -487,7 +487,6 @@ void reinitBluetooth()
DEBUG_MSG("Starting bluetooth\n");
if (isFirstTime) {
bluetoothPhoneAPI = new BluetoothPhoneAPI();
- bluetoothPhoneAPI->init();
}
// FIXME - if waking from light sleep, only esp_nimble_hci_init?
diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp
index bcd74e10c..e67607c94 100644
--- a/src/nrf52/NRF52Bluetooth.cpp
+++ b/src/nrf52/NRF52Bluetooth.cpp
@@ -2,9 +2,9 @@
#include "BluetoothCommon.h"
#include "configuration.h"
#include "main.h"
-#include
-#include "mesh/mesh-pb-constants.h"
#include "mesh/PhoneAPI.h"
+#include "mesh/mesh-pb-constants.h"
+#include
static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
@@ -155,7 +155,6 @@ void fromNumAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt
void setupMeshService(void)
{
bluetoothPhoneAPI = new BluetoothPhoneAPI();
- bluetoothPhoneAPI->init();
meshBleService.begin();
diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp
index 69e96875c..30016484e 100644
--- a/src/plugins/AdminPlugin.cpp
+++ b/src/plugins/AdminPlugin.cpp
@@ -77,6 +77,13 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag
handleGetRadio(mp);
break;
+ case AdminMessage_reboot_seconds_tag: {
+ int32_t s = r->reboot_seconds;
+ DEBUG_MSG("Rebooting in %d seconds\n", s);
+ rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
+ break;
+ }
+
#ifdef PORTDUINO
case AdminMessage_exit_simulator_tag:
DEBUG_MSG("Exiting simulator\n");
diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp
index b6f76ad72..2aaa31a5e 100644
--- a/src/plugins/PositionPlugin.cpp
+++ b/src/plugins/PositionPlugin.cpp
@@ -10,10 +10,8 @@ PositionPlugin *positionPlugin;
PositionPlugin::PositionPlugin()
: ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionPlugin")
{
- isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
- setIntervalFromNow(60 *
- 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
-
+ isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
+ setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
}
bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position *pptr)
diff --git a/version.properties b/version.properties
index 81be22bfa..71cb4d0eb 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 1
minor = 2
-build = 13
+build = 16