kopia lustrzana https://github.com/meshtastic/firmware
commit
7f7b07ce9d
|
@ -199,7 +199,7 @@ We'd love to have you join us on this merry little project. Please see our [deve
|
|||
|
||||
# Credits
|
||||
|
||||
This project is run by volunteers. Past contributors include:
|
||||
This project is run by volunteers. We are a friendly group and welcome any contribution (code fixes, documentation, features, bug reports etc...). We try to be good about listing contributor names in release notes, but it has become unwieldy for the main-devs to keep updating the list below and we've neglected it too long. If you'd like your name included in this list please send a pull request to edit this README and simply add your line yourself. Thank you very much for your help!
|
||||
|
||||
- @astro-arphid: Added support for 433MHz radios in europe.
|
||||
- @claesg: Various documentation fixes and 3D print enclosures
|
||||
|
|
|
@ -4,11 +4,20 @@ You probably don't care about this section - skip to the next one.
|
|||
|
||||
## before next release
|
||||
|
||||
* DONE naks are being dropped (though enqueuedLocal) sometimes before phone/PC gets them
|
||||
* 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
|
||||
|
|
2
proto
2
proto
|
@ -1 +1 @@
|
|||
Subproject commit 820fa497dfde07e129cad6955bf2f4b2b9cecebc
|
||||
Subproject commit 0ea232802651fd6aaa53c93c09f4c2eb36470dd0
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "configuration.h"
|
||||
#include "../freertosinc.h"
|
||||
|
||||
namespace concurrency
|
||||
|
@ -28,4 +27,4 @@ class BinarySemaphoreFreeRTOS
|
|||
|
||||
#endif
|
||||
|
||||
}
|
||||
} // namespace concurrency
|
|
@ -1,5 +1,6 @@
|
|||
#include "NotifiedWorkerThread.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace concurrency
|
||||
|
@ -28,6 +29,7 @@ IRAM_ATTR bool NotifiedWorkerThread::notifyCommon(uint32_t v, bool overwrite)
|
|||
if (overwrite || notification == 0) {
|
||||
enabled = true;
|
||||
setInterval(0); // Run ASAP
|
||||
runASAP = true;
|
||||
|
||||
notification = v;
|
||||
if (debugNotification)
|
||||
|
|
|
@ -457,7 +457,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
void reinitUpdateService();
|
||||
|
||||
void bluetoothRebootCheck();
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
@ -97,7 +97,6 @@ void esp32Loop()
|
|||
{
|
||||
esp_task_wdt_reset(); // service our app level watchdog
|
||||
loopBLE();
|
||||
bluetoothRebootCheck();
|
||||
|
||||
// for debug printing
|
||||
// radio.radioIf.canSleep();
|
||||
|
|
|
@ -717,6 +717,7 @@ void Screen::handleSetOn(bool on)
|
|||
dispdev.displayOn();
|
||||
enabled = true;
|
||||
setInterval(0); // Draw ASAP
|
||||
runASAP = true;
|
||||
} else {
|
||||
DEBUG_MSG("Turning off screen\n");
|
||||
dispdev.displayOff();
|
||||
|
@ -1053,6 +1054,7 @@ void Screen::setFastFramerate()
|
|||
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
||||
ui.setTargetFPS(targetFramerate);
|
||||
setInterval(0); // redraw ASAP
|
||||
runASAP = true;
|
||||
}
|
||||
|
||||
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
|
|
50
src/main.cpp
50
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,13 +576,29 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will supress the current delay and instead try to run ASAP.
|
||||
bool runASAP;
|
||||
|
||||
void loop()
|
||||
{
|
||||
// axpDebugOutput.loop();
|
||||
runASAP = false;
|
||||
|
||||
#ifdef DEBUG_PORT
|
||||
DEBUG_PORT.loop(); // Send/receive protobufs over the serial port
|
||||
#endif
|
||||
// axpDebugOutput.loop();
|
||||
|
||||
// heap_caps_check_integrity_all(true); // FIXME - disable this expensive check
|
||||
|
||||
|
@ -592,6 +608,7 @@ void loop()
|
|||
#ifdef NRF52_SERIES
|
||||
nrf52Loop();
|
||||
#endif
|
||||
rebootCheck();
|
||||
|
||||
// For debugging
|
||||
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
|
||||
|
@ -616,6 +633,7 @@ void loop()
|
|||
mainController.nextThread->tillRun(millis())); */
|
||||
|
||||
// We want to sleep as long as possible here - because it saves power
|
||||
mainDelay.delay(delayMsec);
|
||||
if (!runASAP)
|
||||
mainDelay.delay(delayMsec);
|
||||
// if (didWake) DEBUG_MSG("wake!\n");
|
||||
}
|
||||
|
|
|
@ -20,4 +20,10 @@ extern graphics::Screen *screen;
|
|||
// Return a human readable string of the form "Meshtastic_ab13"
|
||||
const char *getDeviceName();
|
||||
|
||||
extern uint32_t rebootAtMsec;
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will supress the current delay and instead try to run ASAP.
|
||||
extern bool runASAP;
|
||||
|
||||
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop();
|
||||
|
|
|
@ -36,6 +36,7 @@ MeshPacket *MeshPlugin::allocAckNak(Routing_Error err, NodeNum to, PacketId idFr
|
|||
Routing c = Routing_init_default;
|
||||
|
||||
c.error_reason = err;
|
||||
c.which_variant = Routing_error_reason_tag;
|
||||
|
||||
// Now that we have moded sendAckNak up one level into the class heirarchy we can no longer assume we are a RoutingPlugin
|
||||
// So we manually call pb_encode_to_bytes and specify routing port number
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 <assert.h>
|
||||
|
||||
#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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -79,9 +79,10 @@ class ReliableRouter : public FloodingRouter
|
|||
/** Do our retransmission handling */
|
||||
virtual int32_t runOnce()
|
||||
{
|
||||
auto d = FloodingRouter::runOnce();
|
||||
// Note: We must doRetransmissions FIRST, because it might queue up work for the base class runOnce implementation
|
||||
auto d = doRetransmissions();
|
||||
|
||||
int32_t r = doRetransmissions();
|
||||
int32_t r = FloodingRouter::runOnce();
|
||||
|
||||
return min(d, r);
|
||||
}
|
||||
|
@ -109,7 +110,6 @@ class ReliableRouter : public FloodingRouter
|
|||
PendingPacket *startRetransmission(MeshPacket *p);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Stop any retransmissions we are doing of the specified node/packet ID pair
|
||||
*
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
|
||||
|
@ -55,9 +56,11 @@ int32_t Router::runOnce()
|
|||
{
|
||||
MeshPacket *mp;
|
||||
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) {
|
||||
// printPacket("handle fromRadioQ", mp);
|
||||
perhapsHandleReceived(mp);
|
||||
}
|
||||
|
||||
// DEBUG_MSG("sleeping forever!\n");
|
||||
return INT32_MAX; // Wait a long time - until we get woken for the message queue
|
||||
}
|
||||
|
||||
|
@ -117,7 +120,9 @@ void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
|
|||
|
||||
void Router::setReceivedMessage()
|
||||
{
|
||||
// DEBUG_MSG("set interval to ASAP\n");
|
||||
setInterval(0); // Run ASAP, so we can figure out our correct sleep time
|
||||
runASAP = true;
|
||||
}
|
||||
|
||||
ErrorCode Router::sendLocal(MeshPacket *p)
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <HTTPBodyParser.hpp>
|
||||
#include <HTTPMultipartBodyParser.hpp>
|
||||
#include <HTTPURLEncodedBodyParser.hpp>
|
||||
#include <Preferences.h>
|
||||
#include <SPIFFS.h>
|
||||
|
||||
#ifndef NO_ESP32
|
||||
|
@ -837,11 +836,6 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
|||
ResourceParameters *params = req->getParams();
|
||||
std::string content;
|
||||
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
|
||||
uint32_t rebootCounter = preferences.getUInt("rebootCounter", 0);
|
||||
|
||||
if (!params->getQueryParameter("content", content)) {
|
||||
content = "json";
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "StreamAPI.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include <WiFi.h>
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
#include "BluetoothCommon.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include <bluefruit.h>
|
||||
#include "mesh/mesh-pb-constants.h"
|
||||
#include "mesh/PhoneAPI.h"
|
||||
#include "mesh/mesh-pb-constants.h"
|
||||
#include <bluefruit.h>
|
||||
|
||||
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();
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[VERSION]
|
||||
major = 1
|
||||
minor = 2
|
||||
build = 13
|
||||
build = 17
|
||||
|
|
Ładowanie…
Reference in New Issue