diff --git a/bin/version.sh b/bin/version.sh index feeef0162..ef346111c 100644 --- a/bin/version.sh +++ b/bin/version.sh @@ -1,3 +1,3 @@ -export VERSION=1.1.3 \ No newline at end of file +export VERSION=1.1.4 \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 366441bec..3b7c6abb7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -60,14 +60,13 @@ debug_tool = jlink lib_deps = https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306 - 1260 ; OneButton library for non-blocking button debounce + https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39 https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad https://github.com/meshtastic/RadioLib.git#8657380241bce681c33aab46598bbf13b11f876c https://github.com/meshtastic/TinyGPSPlus.git https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460 - https://github.com/meshtastic/esp32_https_server.git Wire ; explicitly needed here because the AXP202 library forgets to add it SPI https://github.com/geeksville/ArduinoThread.git#333ffd09b596977c217ba25da4258f588b462ac6 @@ -96,6 +95,9 @@ build_flags = ${arduino_base.build_flags} -Wall -Wextra -Isrc/esp32 -Isrc/esp32-mfix-esp32-psram-cache-issue -lnimble -std=c++11 -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -DAXP_DEBUG_PORT=Serial +lib_deps = + ${arduino_base.lib_deps} + https://github.com/meshtastic/esp32_https_server.git # Hmm - this doesn't work yet # board_build.ldscript = linker/esp32.extram.bss.ld lib_ignore = segger_rtt diff --git a/src/Power.cpp b/src/Power.cpp index 162047fa3..12a638119 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -138,38 +138,39 @@ int32_t Power::runOnce() { readPowerStatus(); -#ifdef PMU_IRQ - if (pmu_irq) { - pmu_irq = false; - axp.readIRQ(); +#ifdef TBEAM_V10 + // WE no longer use the IRQ line to wake the CPU (due to false wakes from sleep), but we do poll + // the IRQ status by reading the registers over I2C + axp.readIRQ(); - DEBUG_MSG("pmu irq!\n"); - - if (axp.isChargingIRQ()) { - DEBUG_MSG("Battery start charging\n"); - } - if (axp.isChargingDoneIRQ()) { - DEBUG_MSG("Battery fully charged\n"); - } - if (axp.isVbusRemoveIRQ()) { - DEBUG_MSG("USB unplugged\n"); - powerFSM.trigger(EVENT_POWER_DISCONNECTED); - } - if (axp.isVbusPlugInIRQ()) { - DEBUG_MSG("USB plugged In\n"); - powerFSM.trigger(EVENT_POWER_CONNECTED); - } - if (axp.isBattPlugInIRQ()) { - DEBUG_MSG("Battery inserted\n"); - } - if (axp.isBattRemoveIRQ()) { - DEBUG_MSG("Battery removed\n"); - } - if (axp.isPEKShortPressIRQ()) { - DEBUG_MSG("PEK short button press\n"); - } - axp.clearIRQ(); + if (axp.isVbusRemoveIRQ()) { + DEBUG_MSG("USB unplugged\n"); + powerFSM.trigger(EVENT_POWER_DISCONNECTED); } + if (axp.isVbusPlugInIRQ()) { + DEBUG_MSG("USB plugged In\n"); + powerFSM.trigger(EVENT_POWER_CONNECTED); + } + /* + Other things we could check if we cared... + + if (axp.isChargingIRQ()) { + DEBUG_MSG("Battery start charging\n"); + } + if (axp.isChargingDoneIRQ()) { + DEBUG_MSG("Battery fully charged\n"); + } + if (axp.isBattPlugInIRQ()) { + DEBUG_MSG("Battery inserted\n"); + } + if (axp.isBattRemoveIRQ()) { + DEBUG_MSG("Battery removed\n"); + } + if (axp.isPEKShortPressIRQ()) { + DEBUG_MSG("PEK short button press\n"); + } + */ + axp.clearIRQ(); #endif // Only read once every 20 seconds once the power status for the app has been initialized diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 79d5af4dc..6295b9dd4 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -118,13 +118,21 @@ static void serialEnter() { setBluetoothEnable(false); screen->setOn(true); + screen->print("Using API...\n"); } static void powerEnter() { screen->setOn(true); setBluetoothEnable(true); - setCPUFast(true); // Set CPU to 240mhz when we're plugged in to wall power. + screen->print("Powered...\n"); +} + +static void powerExit() +{ + screen->setOn(true); + setBluetoothEnable(true); + screen->print("Unpowered...\n"); } static void onEnter() @@ -158,8 +166,7 @@ State stateDARK(darkEnter, NULL, NULL, "DARK"); State stateSERIAL(serialEnter, NULL, NULL, "SERIAL"); State stateBOOT(bootEnter, NULL, NULL, "BOOT"); State stateON(onEnter, NULL, NULL, "ON"); -State statePOWER(powerEnter, NULL, NULL, "POWER"); - +State statePOWER(powerEnter, NULL, powerExit, "POWER"); Fsm powerFSM(&stateBOOT); void PowerFSM_setup() diff --git a/src/PowerFSM.h b/src/PowerFSM.h index d996acbd3..4af62040c 100644 --- a/src/PowerFSM.h +++ b/src/PowerFSM.h @@ -20,6 +20,6 @@ #define EVENT_POWER_DISCONNECTED 14 extern Fsm powerFSM; -extern State statePOWER; +extern State statePOWER, stateSERIAL; void PowerFSM_setup(); diff --git a/src/concurrency/InterruptableDelay.cpp b/src/concurrency/InterruptableDelay.cpp index e7538235e..80743cc22 100644 --- a/src/concurrency/InterruptableDelay.cpp +++ b/src/concurrency/InterruptableDelay.cpp @@ -4,30 +4,22 @@ namespace concurrency { -InterruptableDelay::InterruptableDelay() -{ -} +InterruptableDelay::InterruptableDelay() {} -InterruptableDelay::~InterruptableDelay() -{ -} +InterruptableDelay::~InterruptableDelay() {} /** * Returns false if we were interrupted */ bool InterruptableDelay::delay(uint32_t msec) { - if (msec) { - // DEBUG_MSG("delay %u ", msec); + // DEBUG_MSG("delay %u ", msec); - // sem take will return false if we timed out (i.e. were not interrupted) - bool r = semaphore.take(msec); + // sem take will return false if we timed out (i.e. were not interrupted) + bool r = semaphore.take(msec); - // DEBUG_MSG("interrupt=%d\n", r); - return !r; - } else { - return true; - } + // DEBUG_MSG("interrupt=%d\n", r); + return !r; } void InterruptableDelay::interrupt() diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 96e18ac5b..e4007aeac 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -202,7 +202,7 @@ class Screen : public concurrency::OSThread return true; // claim success if our display is not in use else { bool success = cmdQueue.enqueue(cmd, 0); - setInterval(0); // handle ASAP + enabled = true; // handle ASAP (we are the registered reader for cmdQueue, but might have been disabled) return success; } } diff --git a/src/main.cpp b/src/main.cpp index 93c9558ed..e258ec521 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -128,31 +128,13 @@ class PowerFSMThread : public OSThread /// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake /// cpu for serial rx - FIXME) - canSleep = (powerFSM.getState() != &statePOWER); - + auto state = powerFSM.getState(); + canSleep = (state != &statePOWER) && (state != &stateSERIAL); + return 10; } }; -static Periodic *ledPeriodic; -static OSThread *powerFSMthread; - -// Prepare for button presses -#ifdef BUTTON_PIN -OneButton userButton; -#endif -#ifdef BUTTON_PIN_ALT -OneButton userButtonAlt; -#endif -void userButtonPressed() -{ - powerFSM.trigger(EVENT_PRESS); -} -void userButtonPressedLong() -{ - screen->adjustBrightness(); -} - /** * Watch a GPIO and if we get an IRQ, wake the main thread. * Use to add wake on button press @@ -168,6 +150,65 @@ void wakeOnIrq(int irq, int mode) FALLING); } +class ButtonThread : public OSThread +{ +// Prepare for button presses +#ifdef BUTTON_PIN + OneButton userButton; +#endif +#ifdef BUTTON_PIN_ALT + OneButton userButtonAlt; +#endif + + public: + // callback returns the period for the next callback invocation (or 0 if we should no longer be called) + ButtonThread() : OSThread("Button") + { +#ifdef BUTTON_PIN + userButton = OneButton(BUTTON_PIN, true, true); + userButton.attachClick(userButtonPressed); + userButton.attachDuringLongPress(userButtonPressedLong); + wakeOnIrq(BUTTON_PIN, FALLING); +#endif +#ifdef BUTTON_PIN_ALT + userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true); + userButtonAlt.attachClick(userButtonPressed); + userButton.attachDuringLongPress(userButtonPressedLong); + wakeOnIrq(BUTTON_PIN_ALT, FALLING); +#endif + } + + protected: + /// If the button is pressed we suppress CPU sleep until release + int32_t runOnce() + { + canSleep = true; // Assume we should not keep the board awake + +#ifdef BUTTON_PIN + userButton.tick(); + canSleep &= userButton.isIdle(); +#endif +#ifdef BUTTON_PIN_ALT + userButtonAlt.tick(); + canSleep &= userButton.isIdle(); +#endif + // if(!canSleep) DEBUG_MSG("Supressing sleep!\n"); + + return 5; + } + + private: + static void userButtonPressed() + { + // DEBUG_MSG("press!\n"); + powerFSM.trigger(EVENT_PRESS); + } + static void userButtonPressedLong() { screen->adjustBrightness(); } +}; + +static Periodic *ledPeriodic; +static OSThread *powerFSMthread, *buttonThread; + RadioInterface *rIf = NULL; void setup() @@ -210,18 +251,7 @@ void setup() #endif // Buttons & LED -#ifdef BUTTON_PIN - userButton = OneButton(BUTTON_PIN, true, true); - userButton.attachClick(userButtonPressed); - userButton.attachDuringLongPress(userButtonPressedLong); - wakeOnIrq(BUTTON_PIN, FALLING); -#endif -#ifdef BUTTON_PIN_ALT - userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true); - userButtonAlt.attachClick(userButtonPressed); - userButton.attachDuringLongPress(userButtonPressedLong); - wakeOnIrq(BUTTON_PIN_ALT, FALLING); -#endif + buttonThread = new ButtonThread(); #ifdef LED_PIN pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, 1 ^ LED_INVERTED); // turn on for now @@ -411,13 +441,6 @@ void loop() esp32Loop(); #endif -#ifdef BUTTON_PIN - userButton.tick(); -#endif -#ifdef BUTTON_PIN_ALT - userButtonAlt.tick(); -#endif - // For debugging // if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving(); @@ -438,9 +461,9 @@ void loop() /* if (mainController.nextThread && delayMsec) DEBUG_MSG("Next %s in %ld\n", mainController.nextThread->ThreadName.c_str(), - mainController.nextThread->tillRun(millis())); - */ - + mainController.nextThread->tillRun(millis())); */ + // We want to sleep as long as possible here - because it saves power mainDelay.delay(delayMsec); + // if (didWake) DEBUG_MSG("wake!\n"); } diff --git a/src/meshwifi/meshhttp.cpp b/src/meshwifi/meshhttp.cpp index eb4fca952..497779139 100644 --- a/src/meshwifi/meshhttp.cpp +++ b/src/meshwifi/meshhttp.cpp @@ -3,6 +3,7 @@ #include "configuration.h" #include "main.h" #include "meshwifi/meshwifi.h" +#include "sleep.h" #include #include @@ -30,6 +31,8 @@ Preferences prefs; #include #include +#define HEADER_LEN 4 + // The HTTPS Server comes in a separate namespace. For easier use, include it here. using namespace httpsserver; @@ -37,16 +40,25 @@ SSLCert *cert; HTTPSServer *secureServer; HTTPServer *insecureServer; +// Our API to handle messages to and from the radio. +httpAPI webAPI; + // Declare some handler functions for the various URLs on the server +void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res); +void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res); void handleStyleCSS(HTTPRequest *req, HTTPResponse *res); void handleJSONChatHistoryDummy(HTTPRequest *req, HTTPResponse *res); void handleHotspot(HTTPRequest *req, HTTPResponse *res); void handleRoot(HTTPRequest *req, HTTPResponse *res); void handle404(HTTPRequest *req, HTTPResponse *res); +void middlewareLogging(HTTPRequest *req, HTTPResponse *res, std::function next); + bool isWebServerReady = 0; bool isCertReady = 0; +uint32_t timeSpeedUp = 0; + void handleWebResponse() { if (isWifiAvailable() == 0) { @@ -61,6 +73,14 @@ void handleWebResponse() secureServer->loop(); insecureServer->loop(); } + + // Slow down the CPU if we have not received a request within the last + // 2 minutes. + if (millis () - timeSpeedUp >= (2 * 60 * 1000)) { + setCPUFast(false); // Set CPU to 80mhz + timeSpeedUp = millis(); + } + } void taskCreateCert(void *parameter) @@ -87,10 +107,10 @@ void taskCreateCert(void *parameter) DEBUG_MSG("Creating the certificate. This may take a while. Please wait...\n"); cert = new SSLCert(); - //disableCore1WDT(); + // disableCore1WDT(); int createCertResult = createSelfSignedCert(*cert, KEYSIZE_2048, "CN=meshtastic.local,O=Meshtastic,C=US", "20190101000000", "20300101000000"); - //enableCore1WDT(); + // enableCore1WDT(); if (createCertResult != 0) { DEBUG_MSG("Creating the certificate failed\n"); @@ -188,6 +208,8 @@ void initWebServer() // For every resource available on the server, we need to create a ResourceNode // The ResourceNode links URL and HTTP method to a handler function + ResourceNode *nodeAPIv1ToRadio = new ResourceNode("/api/v1/toradio", "GET", &handleAPIv1ToRadio); + ResourceNode *nodeAPIv1FromRadio = new ResourceNode("/api/v1/fromradio", "GET", &handleAPIv1FromRadio); ResourceNode *nodeCSS = new ResourceNode("/css/style.css", "GET", &handleStyleCSS); ResourceNode *nodeJS = new ResourceNode("/scripts/script.js", "GET", &handleJSONChatHistoryDummy); ResourceNode *nodeHotspot = new ResourceNode("/hotspot-detect.html", "GET", &handleHotspot); @@ -195,13 +217,19 @@ void initWebServer() ResourceNode *node404 = new ResourceNode("", "GET", &handle404); // Secure nodes + secureServer->registerNode(nodeAPIv1ToRadio); + secureServer->registerNode(nodeAPIv1FromRadio); secureServer->registerNode(nodeCSS); secureServer->registerNode(nodeJS); secureServer->registerNode(nodeHotspot); secureServer->registerNode(nodeRoot); secureServer->setDefaultNode(node404); + secureServer->addMiddleware(&middlewareLogging); + // Insecure nodes + insecureServer->registerNode(nodeAPIv1ToRadio); + insecureServer->registerNode(nodeAPIv1FromRadio); insecureServer->registerNode(nodeCSS); insecureServer->registerNode(nodeJS); insecureServer->registerNode(nodeHotspot); @@ -217,6 +245,16 @@ void initWebServer() } } +void middlewareLogging(HTTPRequest *req, HTTPResponse *res, std::function next) +{ + // We want to print the response status, so we need to call next() first. + next(); + + setCPUFast(true); // Set CPU to 240mhz when we're plugged in to wall power. + timeSpeedUp = millis(); + +} + void handle404(HTTPRequest *req, HTTPResponse *res) { @@ -261,6 +299,40 @@ void handleHotspot(HTTPRequest *req, HTTPResponse *res) res->println("\n"); } +void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) +{ + DEBUG_MSG("+++++++++++++++ webAPI handleAPIv1FromRadio\n"); + + /* + http://10.10.30.198/api/v1/fromradio + + */ + + // Status code is 200 OK by default. + // We want to deliver a simple HTML page, so we send a corresponding content type: + res->setHeader("Content-Type", "application/x-protobuf"); + + uint8_t txBuf[MAX_STREAM_BUF_SIZE]; + + uint32_t len = webAPI.getFromRadio(txBuf + HEADER_LEN); + + res->write(txBuf, len); + DEBUG_MSG("--------------- webAPI handleAPIv1FromRadio, len %d\n", len); +} + +void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res) +{ + DEBUG_MSG("webAPI handleAPIv1ToRadio\n"); + + // Status code is 200 OK by default. + // We want to deliver a simple HTML page, so we send a corresponding content type: + res->setHeader("Content-Type", "application/x-protobuf"); + + // The response implements the Print interface, so you can use it just like + // you would write to Serial etc. + res->print(""); +} + /* To convert text to c strings: diff --git a/src/meshwifi/meshhttp.h b/src/meshwifi/meshhttp.h index eeddfe9ff..42bb1d3bc 100644 --- a/src/meshwifi/meshhttp.h +++ b/src/meshwifi/meshhttp.h @@ -2,11 +2,11 @@ #include #include +#include "PhoneAPI.h" void initWebServer(); void createSSLCert(); - void handleNotFound(); void handleWebResponse(); @@ -17,8 +17,21 @@ void notifyWebUI(); void handleHotspot(); - void handleStyleCSS(); void handleRoot(); void handleScriptsScriptJS(); -void handleJSONChatHistoryDummy(); \ No newline at end of file +void handleJSONChatHistoryDummy(); + +class httpAPI : public PhoneAPI +{ + +public: + // Nothing here yet + +private: + // Nothing here yet + +protected: + // Nothing here yet + +}; \ No newline at end of file diff --git a/src/meshwifi/meshwifi.cpp b/src/meshwifi/meshwifi.cpp index 6ba32df86..3026b13f1 100644 --- a/src/meshwifi/meshwifi.cpp +++ b/src/meshwifi/meshwifi.cpp @@ -17,7 +17,7 @@ static WiFiServerPort *apiPort; uint8_t wifiDisconnectReason = 0; -// Stores the last 4 of our hardware ID, to make finding the device for pairing easier +// Stores our hostname static char ourHost[16]; bool isWifiAvailable()