diff --git a/platformio.ini b/platformio.ini index 34667d2c..1f962a8d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,8 +9,13 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] +;default_envs = tbeam +;default_envs = tbeam0.7 +;default_envs = heltec +;default_envs = tlora-v1 +;default_envs = tlora-v2 +;default_envs = lora-relay-v1 # nrf board default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here -;default_envs = heltec # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] ; common is not currently used @@ -183,7 +188,7 @@ build_flags = -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3 ;-DCFG_DEBUG=3 src_filter = - ${arduino_base.src_filter} - - - - + ${arduino_base.src_filter} - - - - lib_ignore = BluetoothOTA monitor_port = /dev/ttyACM1 @@ -310,7 +315,7 @@ lib_deps = ; The Portduino based sim environment on top of linux [env:linux] platform = https://github.com/geeksville/platform-portduino.git -src_filter = ${env.src_filter} - - - - +src_filter = ${env.src_filter} - - - - build_flags = ${arduino_base.build_flags} -O0 framework = arduino board = linux_x86_64 diff --git a/proto b/proto index dfe7bc12..75078afe 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit dfe7bc1217a00c23eecb9dfcf1d56fe95ebddc3b +Subproject commit 75078afe43934f4ce15ef86ebc6950658a170145 diff --git a/src/PowerStatus.h b/src/PowerStatus.h index e9c192fb..a276be59 100644 --- a/src/PowerStatus.h +++ b/src/PowerStatus.h @@ -11,7 +11,7 @@ namespace meshtastic */ enum OptionalBool { OptFalse = 0, OptTrue = 1, OptUnknown = 2 }; -/// Describes the state of the GPS system. +/// Describes the state of the Power system. class PowerStatus : public Status { diff --git a/src/airtime.cpp b/src/airtime.cpp index ec0bf8c8..8d1800d5 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -3,33 +3,35 @@ #define periodsToLog 48 -// A reminder that there are 3600 seconds in an hour so I don't have -// to keep googling it. -// This can be changed to a smaller number to speed up testing. -// +AirTime *airTime; + uint32_t secondsPerPeriod = 3600; uint32_t lastMillis = 0; uint32_t secSinceBoot = 0; +// AirTime at; + // Don't read out of this directly. Use the helper functions. struct airtimeStruct { - uint16_t periodTX[periodsToLog]; - uint16_t periodRX[periodsToLog]; - uint16_t periodRX_ALL[periodsToLog]; + uint32_t periodTX[periodsToLog]; // AirTime transmitted + uint32_t periodRX[periodsToLog]; // AirTime received and repeated (Only valid mesh packets) + uint32_t periodRX_ALL[periodsToLog]; // AirTime received regardless of valid mesh packet. Could include noise. uint8_t lastPeriodIndex; } airtimes; -void logAirtime(reportTypes reportType, uint32_t airtime_ms) +void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms) { - if (reportType == TX_LOG) { - airtimes.periodTX[0] = airtimes.periodTX[0] + round(airtime_ms / 1000); + DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms); + airtimes.periodTX[0] = airtimes.periodTX[0] + airtime_ms; } else if (reportType == RX_LOG) { - airtimes.periodRX[0] = airtimes.periodRX[0] + round(airtime_ms / 1000); + DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms); + airtimes.periodRX[0] = airtimes.periodRX[0] + airtime_ms; } else if (reportType == RX_ALL_LOG) { - airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + round(airtime_ms / 1000); + DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms); + airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + airtime_ms; } else { - // Unknown report type + DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n"); } } @@ -38,29 +40,27 @@ uint8_t currentPeriodIndex() return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog); } -void airtimeCalculator() +void airtimeRotatePeriod() { - if (millis() - lastMillis > 1000) { - lastMillis = millis(); - secSinceBoot++; - if (airtimes.lastPeriodIndex != currentPeriodIndex()) { - for (int i = periodsToLog - 2; i >= 0; --i) { - airtimes.periodTX[i + 1] = airtimes.periodTX[i]; - airtimes.periodRX[i + 1] = airtimes.periodRX[i]; - airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i]; - } - airtimes.periodTX[0] = 0; - airtimes.periodRX[0] = 0; - airtimes.periodRX_ALL[0] = 0; - airtimes.lastPeriodIndex = currentPeriodIndex(); + if (airtimes.lastPeriodIndex != currentPeriodIndex()) { + DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex()); + + for (int i = periodsToLog - 2; i >= 0; --i) { + airtimes.periodTX[i + 1] = airtimes.periodTX[i]; + airtimes.periodRX[i + 1] = airtimes.periodRX[i]; + airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i]; } + airtimes.periodTX[0] = 0; + airtimes.periodRX[0] = 0; + airtimes.periodRX_ALL[0] = 0; + + airtimes.lastPeriodIndex = currentPeriodIndex(); } } -uint16_t *airtimeReport(reportTypes reportType) +uint32_t *airtimeReport(reportTypes reportType) { - // currentHourIndexReset(); if (reportType == TX_LOG) { return airtimes.periodTX; @@ -86,3 +86,22 @@ uint32_t getSecondsSinceBoot() { return secSinceBoot; } + +AirTime::AirTime() : concurrency::OSThread("AirTime") {} + +int32_t AirTime::runOnce() +{ + //DEBUG_MSG("AirTime::runOnce()\n"); + + airtimeRotatePeriod(); + secSinceBoot++; + + /* + This actually doesn't need to be run once per second but we currently use it for the + secSinceBoot counter. + + If we have a better counter of how long the device has been online (and not millis()) + then we can change this to something less frequent. Maybe once ever 5 seconds? + */ + return (1000 * 1); +} \ No newline at end of file diff --git a/src/airtime.h b/src/airtime.h index 4cfbb82c..d78db86a 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -1,5 +1,6 @@ #pragma once +#include "concurrency/OSThread.h" #include "configuration.h" #include #include @@ -18,7 +19,7 @@ TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel. TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including - other lora radios. + other lora radios. RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel. */ @@ -26,13 +27,28 @@ enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG }; void logAirtime(reportTypes reportType, uint32_t airtime_ms); -void airtimeCalculator(); +void airtimeRotatePeriod(); uint8_t currentPeriodIndex(); uint8_t getPeriodsToLog(); uint32_t getSecondsSinceBoot(); -uint16_t *airtimeReport(reportTypes reportType); +uint32_t *airtimeReport(reportTypes reportType); -uint32_t getSecondsPerPeriod(); \ No newline at end of file +uint32_t getSecondsPerPeriod(); + +class AirTime : private concurrency::OSThread +{ + + public: + AirTime(); + + void logAirtime(reportTypes reportType, uint32_t airtime_ms); + + protected: + + virtual int32_t runOnce(); +}; + +extern AirTime *airTime; \ No newline at end of file diff --git a/src/graphics/EInkDisplay.cpp b/src/graphics/EInkDisplay.cpp index 0d5e8307..2b530c0c 100644 --- a/src/graphics/EInkDisplay.cpp +++ b/src/graphics/EInkDisplay.cpp @@ -4,7 +4,6 @@ #include "EInkDisplay.h" #include "SPILock.h" #include "epd1in54.h" // Screen specific library -#include "graphics/configs.h" #include #include // Graphics library and Sprite class diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 34ab53ac..6f022943 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -31,11 +31,14 @@ along with this program. If not, see . #include "graphics/images.h" #include "main.h" #include "mesh-pb-constants.h" -#include "meshwifi/meshwifi.h" #include "plugins/TextMessagePlugin.h" #include "target_specific.h" #include "utils.h" +#ifndef NO_ESP32 +#include "mesh/http/WiFiAPClient.h" +#endif + using namespace meshtastic; /** @todo remove */ namespace graphics @@ -895,10 +898,12 @@ void Screen::setFrames() // call a method on debugInfoScreen object (for more details) normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline; +#ifndef NO_ESP32 if (isWifiAvailable()) { // call a method on debugInfoScreen object (for more details) normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline; } +#endif ui.setFrames(normalFrames, numframes); ui.enableAllIndicators(); diff --git a/src/main.cpp b/src/main.cpp index dffbfc9b..b63c193a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,16 +19,16 @@ #include "concurrency/Periodic.h" #include "graphics/Screen.h" #include "main.h" -#include "meshwifi/meshhttp.h" -#include "meshwifi/meshwifi.h" -#include "sleep.h" #include "plugins/Plugins.h" +#include "sleep.h" #include "target_specific.h" #include #include // #include #ifndef NO_ESP32 +#include "mesh/http/WebServer.h" +#include "mesh/http/WiFiAPClient.h" #include "nimble/BluetoothUtil.h" #endif @@ -513,9 +513,18 @@ void setup() } #endif + +#ifndef NO_ESP32 // Initialize Wifi initWifi(forceSoftAP); + // Start web server thread. + webServerThread = new WebServerThread(); +#endif + + // Start airtime logger thread. + airTime = new AirTime(); + if (!rIf) recordCriticalError(CriticalErrorCode_NoRadio); else @@ -576,7 +585,7 @@ void loop() #endif // TODO: This should go into a thread handled by FreeRTOS. - handleWebResponse(); + // handleWebResponse(); service.loop(); @@ -589,7 +598,4 @@ void loop() // We want to sleep as long as possible here - because it saves power mainDelay.delay(delayMsec); // if (didWake) DEBUG_MSG("wake!\n"); - - // Handles cleanup for the airtime calculator. - airtimeCalculator(); } diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index a87a5e49..dc13bc42 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -16,10 +16,13 @@ #include "configuration.h" #include "error.h" #include "mesh-pb-constants.h" -#include "meshwifi/meshwifi.h" #include #include +#ifndef NO_ESP32 +#include "mesh/http/WiFiAPClient.h" +#endif + NodeDB nodeDB; // we have plenty of ram so statically alloc this tempbuf (for now) diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index f4ceeded..0266614a 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -97,7 +97,8 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) // Count the packet toward our TX airtime utilization. // We only count it if it can be added to the TX queue. - logAirtime(TX_LOG, xmitMsec); + airTime->logAirtime(TX_LOG, xmitMsec); + //airTime.logAirtime(TX_LOG, xmitMsec); // We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent // in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio @@ -216,7 +217,8 @@ void RadioLibInterface::handleReceiveInterrupt() size_t length = iface->getPacketLength(); xmitMsec = getPacketTime(length); - logAirtime(RX_ALL_LOG, xmitMsec); + airTime->logAirtime(RX_ALL_LOG, xmitMsec); + //airTime.logAirtime(RX_ALL_LOG, xmitMsec); int state = iface->readData(radiobuf, length); if (state != ERR_NONE) { @@ -258,7 +260,8 @@ void RadioLibInterface::handleReceiveInterrupt() printPacket("Lora RX", mp); xmitMsec = getPacketTime(mp); - logAirtime(RX_LOG, xmitMsec); + airTime->logAirtime(RX_LOG, xmitMsec); + //airTime.logAirtime(RX_LOG, xmitMsec); deliverToReceiver(mp); } diff --git a/src/mesh/http/ContentHelper.cpp b/src/mesh/http/ContentHelper.cpp new file mode 100644 index 00000000..249dcbde --- /dev/null +++ b/src/mesh/http/ContentHelper.cpp @@ -0,0 +1,14 @@ +#include "mesh/http/ContentHelper.h" +//#include +//#include "main.h" + +void replaceAll(std::string &str, const std::string &from, const std::string &to) +{ + if (from.empty()) + return; + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } +} diff --git a/src/mesh/http/ContentHelper.h b/src/mesh/http/ContentHelper.h new file mode 100644 index 00000000..f94b9816 --- /dev/null +++ b/src/mesh/http/ContentHelper.h @@ -0,0 +1,8 @@ +#include +#include + + + + +void replaceAll(std::string &str, const std::string &from, const std::string &to); + diff --git a/src/meshwifi/meshhttpStatic.h b/src/mesh/http/ContentStatic.h similarity index 98% rename from src/meshwifi/meshhttpStatic.h rename to src/mesh/http/ContentStatic.h index e48aeb41..32427647 100644 --- a/src/meshwifi/meshhttpStatic.h +++ b/src/mesh/http/ContentStatic.h @@ -2,14 +2,7 @@ #include /* - Steps: - - Compress the .js file to .js.gz - - Convert to hex: - http://tomeko.net/online_tools/file_to_hex.php?lang=en - - Paste into the array - - Note the filesize of your .gz file and write the file - size into the length int. - + This file contains static content. */ // Length of the binary data diff --git a/src/meshwifi/meshhttp.cpp b/src/mesh/http/WebServer.cpp similarity index 97% rename from src/meshwifi/meshhttp.cpp rename to src/mesh/http/WebServer.cpp index f4051dd4..1c1b5a82 100644 --- a/src/meshwifi/meshhttp.cpp +++ b/src/mesh/http/WebServer.cpp @@ -1,12 +1,11 @@ -#include "meshwifi/meshhttp.h" +#include "mesh/http/WebServer.h" #include "NodeDB.h" #include "PowerFSM.h" #include "airtime.h" -#include "configuration.h" -#include "esp_task_wdt.h" #include "main.h" -#include "meshhttpStatic.h" -#include "meshwifi/meshwifi.h" +#include "mesh/http/ContentHelper.h" +#include "mesh/http/ContentStatic.h" +#include "mesh/http/WiFiAPClient.h" #include "sleep.h" #include #include @@ -15,6 +14,10 @@ #include #include +#ifndef NO_ESP32 +#include "esp_task_wdt.h" +#endif + // Persistant Data Storage #include Preferences prefs; @@ -196,6 +199,19 @@ void createSSLCert() DEBUG_MSG("SSL Cert Ready!\n"); } +WebServerThread *webServerThread; + +WebServerThread::WebServerThread() : concurrency::OSThread("WebServerThread") {} + +int32_t WebServerThread::runOnce() +{ + // DEBUG_MSG("WebServerThread::runOnce()\n"); + handleWebResponse(); + + // Loop every 5ms. + return (5); +} + void initWebServer() { DEBUG_MSG("Initializing Web Server ...\n"); @@ -241,6 +257,7 @@ void initWebServer() ResourceNode *nodeAPIv1ToRadioOptions = new ResourceNode("/api/v1/toradio", "OPTIONS", &handleAPIv1ToRadio); ResourceNode *nodeAPIv1ToRadio = new ResourceNode("/api/v1/toradio", "PUT", &handleAPIv1ToRadio); ResourceNode *nodeAPIv1FromRadio = new ResourceNode("/api/v1/fromradio", "GET", &handleAPIv1FromRadio); + ResourceNode *nodeHotspot = new ResourceNode("/hotspot-detect.html", "GET", &handleHotspot); ResourceNode *nodeFavicon = new ResourceNode("/favicon.ico", "GET", &handleFavicon); ResourceNode *nodeRoot = new ResourceNode("/", "GET", &handleRoot); @@ -340,6 +357,97 @@ void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::functiongetParams(); + + // std::string paramAll = "all"; + std::string valueAll; + + // Status code is 200 OK by default. + res->setHeader("Content-Type", "application/x-protobuf"); + res->setHeader("Access-Control-Allow-Origin", "*"); + res->setHeader("Access-Control-Allow-Methods", "PUT, GET"); + res->setHeader("X-Protobuf-Schema", "https://raw.githubusercontent.com/meshtastic/Meshtastic-protobufs/master/mesh.proto"); + + uint8_t txBuf[MAX_STREAM_BUF_SIZE]; + uint32_t len = 1; + + if (params->getQueryParameter("all", valueAll)) { + + // If all is ture, return all the buffers we have available + // to us at this point in time. + if (valueAll == "true") { + while (len) { + len = webAPI.getFromRadio(txBuf); + res->write(txBuf, len); + } + + // Otherwise, just return one protobuf + } else { + len = webAPI.getFromRadio(txBuf); + res->write(txBuf, len); + } + + // the param "all" was not spcified. Return just one protobuf + } else { + len = webAPI.getFromRadio(txBuf); + res->write(txBuf, len); + } + + DEBUG_MSG("--------------- webAPI handleAPIv1FromRadio, len %d\n", len); +} + +void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res) +{ + DEBUG_MSG("+++++++++++++++ webAPI handleAPIv1ToRadio\n"); + + /* + For documentation, see: + https://github.com/meshtastic/Meshtastic-device/wiki/HTTP-REST-API-discussion + https://github.com/meshtastic/Meshtastic-device/blob/master/docs/software/device-api.md + + Example: + http://10.10.30.198/api/v1/toradio + */ + + // Status code is 200 OK by default. + + res->setHeader("Content-Type", "application/x-protobuf"); + res->setHeader("Access-Control-Allow-Headers", "Content-Type"); + res->setHeader("Access-Control-Allow-Origin", "*"); + res->setHeader("Access-Control-Allow-Methods", "PUT, OPTIONS"); + res->setHeader("X-Protobuf-Schema", "https://raw.githubusercontent.com/meshtastic/Meshtastic-protobufs/master/mesh.proto"); + + if (req->getMethod() == "OPTIONS") { + res->setStatusCode(204); // Success with no content + res->print(""); + return; + } + + byte buffer[MAX_TO_FROM_RADIO_SIZE]; + size_t s = req->readBytes(buffer, MAX_TO_FROM_RADIO_SIZE); + + DEBUG_MSG("Received %d bytes from PUT request\n", s); + webAPI.handleToRadio(buffer, s); + + res->write(buffer, s); + DEBUG_MSG("--------------- webAPI handleAPIv1ToRadio\n"); +} + void handleStaticPost(HTTPRequest *req, HTTPResponse *res) { // Assume POST request. Contains submitted data. @@ -816,10 +924,10 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res) return; } - //if (readLength) { - file.write(buf, readLength); - fileLength += readLength; - DEBUG_MSG("File Length %i\n", fileLength); + // if (readLength) { + file.write(buf, readLength); + fileLength += readLength; + DEBUG_MSG("File Length %i\n", fileLength); //} } // enableLoopWDT(); @@ -876,97 +984,6 @@ void handleHotspot(HTTPRequest *req, HTTPResponse *res) res->println("\n"); } -void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) -{ - - DEBUG_MSG("+++++++++++++++ webAPI handleAPIv1FromRadio\n"); - - /* - For documentation, see: - https://github.com/meshtastic/Meshtastic-device/wiki/HTTP-REST-API-discussion - https://github.com/meshtastic/Meshtastic-device/blob/master/docs/software/device-api.md - - Example: - http://10.10.30.198/api/v1/fromradio - */ - - // Get access to the parameters - ResourceParameters *params = req->getParams(); - - // std::string paramAll = "all"; - std::string valueAll; - - // Status code is 200 OK by default. - res->setHeader("Content-Type", "application/x-protobuf"); - res->setHeader("Access-Control-Allow-Origin", "*"); - res->setHeader("Access-Control-Allow-Methods", "PUT, GET"); - res->setHeader("X-Protobuf-Schema", "https://raw.githubusercontent.com/meshtastic/Meshtastic-protobufs/master/mesh.proto"); - - uint8_t txBuf[MAX_STREAM_BUF_SIZE]; - uint32_t len = 1; - - if (params->getQueryParameter("all", valueAll)) { - - // If all is ture, return all the buffers we have available - // to us at this point in time. - if (valueAll == "true") { - while (len) { - len = webAPI.getFromRadio(txBuf); - res->write(txBuf, len); - } - - // Otherwise, just return one protobuf - } else { - len = webAPI.getFromRadio(txBuf); - res->write(txBuf, len); - } - - // the param "all" was not spcified. Return just one protobuf - } else { - len = webAPI.getFromRadio(txBuf); - res->write(txBuf, len); - } - - DEBUG_MSG("--------------- webAPI handleAPIv1FromRadio, len %d\n", len); -} - -void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res) -{ - DEBUG_MSG("+++++++++++++++ webAPI handleAPIv1ToRadio\n"); - - /* - For documentation, see: - https://github.com/meshtastic/Meshtastic-device/wiki/HTTP-REST-API-discussion - https://github.com/meshtastic/Meshtastic-device/blob/master/docs/software/device-api.md - - Example: - http://10.10.30.198/api/v1/toradio - */ - - // Status code is 200 OK by default. - - res->setHeader("Content-Type", "application/x-protobuf"); - res->setHeader("Access-Control-Allow-Headers", "Content-Type"); - res->setHeader("Access-Control-Allow-Origin", "*"); - res->setHeader("Access-Control-Allow-Methods", "PUT, OPTIONS"); - res->setHeader("X-Protobuf-Schema", "https://raw.githubusercontent.com/meshtastic/Meshtastic-protobufs/master/mesh.proto"); - - if (req->getMethod() == "OPTIONS") { - res->setStatusCode(204); // Success with no content - res->print(""); - return; - } - - byte buffer[MAX_TO_FROM_RADIO_SIZE]; - size_t s = req->readBytes(buffer, MAX_TO_FROM_RADIO_SIZE); - - DEBUG_MSG("Received %d bytes from PUT request\n", s); - webAPI.handleToRadio(buffer, s); - - res->write(buffer, s); - DEBUG_MSG("--------------- webAPI handleAPIv1ToRadio\n"); -} - /* To convert text to c strings: @@ -996,7 +1013,8 @@ void handleRoot(HTTPRequest *req, HTTPResponse *res) res->printf("

\n"); res->printf("

You have gotten this error because the filesystem for the web server has not been loaded.

\n"); res->printf("

Please review the 'Common Problems' section of the web interface documentation.

\n"); + "href=https://github.com/meshtastic/Meshtastic-device/wiki/" + "How-to-use-the-Meshtastic-Web-Interface-over-WiFi>web interface documentation.

\n"); return; } @@ -1092,13 +1110,13 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->println("\"airtime\": {"); - uint16_t *logArray; + uint32_t *logArray; res->print("\"tx_log\": ["); logArray = airtimeReport(TX_LOG); for (int i = 0; i < getPeriodsToLog(); i++) { - uint16_t tmp; + uint32_t tmp; tmp = *(logArray + i); res->printf("%d", tmp); if (i != getPeriodsToLog() - 1) { @@ -1111,7 +1129,7 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) logArray = airtimeReport(RX_LOG); for (int i = 0; i < getPeriodsToLog(); i++) { - uint16_t tmp; + uint32_t tmp; tmp = *(logArray + i); res->printf("%d", tmp); if (i != getPeriodsToLog() - 1) { @@ -1124,7 +1142,7 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) logArray = airtimeReport(RX_ALL_LOG); for (int i = 0; i < getPeriodsToLog(); i++) { - uint16_t tmp; + uint32_t tmp; tmp = *(logArray + i); res->printf("%d", tmp); if (i != getPeriodsToLog() - 1) { @@ -1151,7 +1169,14 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->println("},"); - res->println("\"test\": 123"); + res->println("\"power\": {"); +#define BoolToString(x) ((x)?"true":"false") + res->printf("\"battery_percent\": %u,\n", powerStatus->getBatteryChargePercent()); + res->printf("\"battery_voltage_mv\": %u,\n", powerStatus->getBatteryVoltageMv()); + res->printf("\"has_battery\": %s,\n", BoolToString(powerStatus->getHasBattery())); + res->printf("\"has_usb\": %s,\n", BoolToString(powerStatus->getHasUSB())); + res->printf("\"is_charging\": %s\n", BoolToString(powerStatus->getIsCharging())); + res->println("}"); res->println("},"); @@ -1209,14 +1234,3 @@ void handleFavicon(HTTPRequest *req, HTTPResponse *res) // Write data from header file res->write(FAVICON_DATA, FAVICON_LENGTH); } - -void replaceAll(std::string &str, const std::string &from, const std::string &to) -{ - if (from.empty()) - return; - size_t start_pos = 0; - while ((start_pos = str.find(from, start_pos)) != std::string::npos) { - str.replace(start_pos, from.length(), to); - start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' - } -} diff --git a/src/mesh/http/WebServer.h b/src/mesh/http/WebServer.h new file mode 100644 index 00000000..b01d5960 --- /dev/null +++ b/src/mesh/http/WebServer.h @@ -0,0 +1,47 @@ +#pragma once + +#include "PhoneAPI.h" +#include "concurrency/OSThread.h" +#include +#include + +void initWebServer(); +void createSSLCert(); + +void handleNotFound(); + +void handleWebResponse(); + + +//void handleHotspot(); + +//void handleStyleCSS(); +//void handleRoot(); + + +// Interface to the PhoneAPI to access the protobufs with messages +class HttpAPI : public PhoneAPI +{ + + public: + // Nothing here yet + + private: + // Nothing here yet + + protected: + // Nothing here yet +}; + +class WebServerThread : private concurrency::OSThread +{ + + public: + WebServerThread(); + + protected: + + virtual int32_t runOnce(); +}; + +extern WebServerThread *webServerThread; diff --git a/src/meshwifi/meshwifi.cpp b/src/mesh/http/WiFiAPClient.cpp similarity index 99% rename from src/meshwifi/meshwifi.cpp rename to src/mesh/http/WiFiAPClient.cpp index 5ae83f87..3ecd7235 100644 --- a/src/meshwifi/meshwifi.cpp +++ b/src/mesh/http/WiFiAPClient.cpp @@ -1,9 +1,9 @@ -#include "meshwifi.h" +#include "mesh/http/WiFiAPClient.h" #include "NodeDB.h" -#include "mesh/wifi/WiFiServerAPI.h" #include "configuration.h" #include "main.h" -#include "meshwifi/meshhttp.h" +#include "mesh/http/WebServer.h" +#include "mesh/wifi/WiFiServerAPI.h" #include "target_specific.h" #include #include diff --git a/src/meshwifi/meshwifi.h b/src/mesh/http/WiFiAPClient.h similarity index 100% rename from src/meshwifi/meshwifi.h rename to src/mesh/http/WiFiAPClient.h diff --git a/src/meshwifi/meshhttp.h b/src/meshwifi/meshhttp.h deleted file mode 100644 index b7a84475..00000000 --- a/src/meshwifi/meshhttp.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "PhoneAPI.h" -#include -#include - -void initWebServer(); -void createSSLCert(); - -void handleNotFound(); - -void handleWebResponse(); - -void handleJSONChatHistory(); - -void notifyWebUI(); - -void handleHotspot(); - -void handleStyleCSS(); -void handleRoot(); -void handleScriptsScriptJS(); -void handleJSONChatHistoryDummy(); - -void replaceAll(std::string& str, const std::string& from, const std::string& to); - -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/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index daba6937..f5f1f77e 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -7,13 +7,16 @@ #include "esp_bt.h" #include "host/util/util.h" #include "main.h" -#include "meshwifi/meshwifi.h" #include "nimble/NimbleDefs.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" #include #include +#ifndef NO_ESP32 +#include "mesh/http/WiFiAPClient.h" +#endif + static bool pinShowing; static uint32_t doublepressed; @@ -545,7 +548,9 @@ void setBluetoothEnable(bool on) if (firstTime) { firstTime = 0; } else { - initWifi(0); +#ifndef NO_ESP32 + initWifi(0); +#endif } } else { @@ -557,7 +562,9 @@ void setBluetoothEnable(bool on) */ // shutdown wifi +#ifndef NO_ESP32 deinitWifi(); +#endif // We have to totally teardown our bluetooth objects to prevent leaks deinitBLE(); diff --git a/src/nrf52/wifi-stubs.cpp b/src/nrf52/wifi-stubs.cpp index 1c100986..6051e195 100644 --- a/src/nrf52/wifi-stubs.cpp +++ b/src/nrf52/wifi-stubs.cpp @@ -1,5 +1,9 @@ -#include "meshwifi/meshhttp.h" -#include "meshwifi/meshwifi.h" +//#include "mesh/wifi/WebServer.h" +#include "configuration.h" + +#ifndef NO_ESP32 + +//#include "mesh/wifi/WiFiAPClient.h" void initWifi(bool forceSoftAP) {} @@ -10,7 +14,4 @@ bool isWifiAvailable() return false; } -void handleWebResponse() {} - -/// Perform idle loop processing required by the wifi layer -void loopWifi() {} \ No newline at end of file +#endif diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 7a43c45f..eee8280c 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -1,6 +1,7 @@ #include "plugins/NodeInfoPlugin.h" #include "plugins/PositionPlugin.h" #include "plugins/ReplyPlugin.h" +#include "plugins/SerialPlugin.h" #include "plugins/RemoteHardwarePlugin.h" #include "plugins/TextMessagePlugin.h" @@ -17,4 +18,5 @@ void setupPlugins() { new RemoteHardwarePlugin(); new ReplyPlugin(); + new SerialPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org } \ No newline at end of file diff --git a/src/plugins/SerialPlugin.cpp b/src/plugins/SerialPlugin.cpp new file mode 100644 index 00000000..82c8baf8 --- /dev/null +++ b/src/plugins/SerialPlugin.cpp @@ -0,0 +1,178 @@ +#include "SerialPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include + +#include + +/* + SerialPlugin + An overly simplistic interface to send messages over the mesh network by sending strings + over a serial port. + + Originally designed for lora32 v1.0 + Manufacture Info: http://www.lilygo.cn/prod_view.aspx?TypeId=50003&Id=1133&FId=t3:50003:3 + Pin Mapping: http://ae01.alicdn.com/kf/HTB1fLBcxkSWBuNjSszdq6zeSpXaJ.jpg + + This will probably and most likely work on other esp32 devices, given possible change the RX/TX + selection. + + Need help with this plugin? Post your question on the Meshtastic Discourse: + https://meshtastic.discourse.group + + Basic Usage: + + 1) Enable the plugin by setting SERIALPLUGIN_ENABLED to 1. + 2) Set the pins (RXD2 / TXD2) for your preferred RX and TX GPIO pins. + 3) Set SERIALPLUGIN_TIMEOUT to the amount of time to wait before we consider + your packet as "done". + 4) (Optional) In SerialPlugin.h set the port to PortNum_TEXT_MESSAGE_APP if you want to + send messages to/from the general text message channel. + 5) Connect to your device over the serial interface at 38400 8N1. + 6) Send a packet up to 240 bytes in length. This will get relayed over the mesh network. + 7) (Optional) Set SERIALPLUGIN_ECHO to 1 and any message you send out will be echoed back + to your device. + + TODO (in this order): + * Add check for esp32 and only build code sections for esp32. + * Once protobufs regenerated with the new port, update SerialPlugin.h + * Ensure this works on a tbeam + * Define a verbose RX mode to report on mesh and packet infomration. + - This won't happen any time soon. + + KNOWN PROBLEMS + * Until the plugin is initilized by the startup sequence, the TX pin is in a floating + state. Device connected to that pin may see this as "noise". + * This will not work on the NRF or Linux target. + + +*/ + +#define RXD2 16 +#define TXD2 17 +#define SERIALPLUGIN_RX_BUFFER 128 +#define SERIALPLUGIN_STRING_MAX Constants_DATA_PAYLOAD_LEN +#define SERIALPLUGIN_TIMEOUT 250 +#define SERIALPLUGIN_BAUD 38400 +#define SERIALPLUGIN_ENABLED 0 +#define SERIALPLUGIN_ECHO 0 +#define SERIALPLUGIN_ACK 0 + +SerialPlugin *serialPlugin; +SerialPluginRadio *serialPluginRadio; + +SerialPlugin::SerialPlugin() : concurrency::OSThread("SerialPlugin") {} + +char serialStringChar[Constants_DATA_PAYLOAD_LEN]; + +int32_t SerialPlugin::runOnce() +{ +#ifdef NO_ESP32 + +#if SERIALPLUGIN_ENABLED == 1 + + if (firstTime) { + + // Interface with the serial peripheral from in here. + DEBUG_MSG("Initilizing serial peripheral interface\n"); + + Serial2.begin(SERIALPLUGIN_BAUD, SERIAL_8N1, RXD2, TXD2); + Serial2.setTimeout(SERIALPLUGIN_TIMEOUT); // Number of MS to wait to set the timeout for the string. + Serial2.setRxBufferSize(SERIALPLUGIN_RX_BUFFER); + + serialPluginRadio = new SerialPluginRadio(); + + firstTime = 0; + + } else { + String serialString; + + while (Serial2.available()) { + serialString = Serial2.readString(); + serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN); + + serialPluginRadio->sendPayload(); + + DEBUG_MSG("Received: %s\n", serialStringChar); + } + } + + return (10); +#else + DEBUG_MSG("Serial Plugin Disabled\n"); + + return (INT32_MAX); +#endif + +#endif +} + +MeshPacket *SerialPluginRadio::allocReply() +{ + + auto reply = allocDataPacket(); // Allocate a packet for sending + + return reply; +} + +void SerialPluginRadio::sendPayload(NodeNum dest, bool wantReplies) +{ + MeshPacket *p = allocReply(); + p->to = dest; + p->decoded.want_response = wantReplies; + + p->want_ack = SERIALPLUGIN_ACK; + + p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply + memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size); + + service.sendToMesh(p); +} + +bool SerialPluginRadio::handleReceived(const MeshPacket &mp) +{ + +#ifdef NO_ESP32 + +#if SERIALPLUGIN_ENABLED == 1 + + auto &p = mp.decoded.data; + // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", nodeDB.getNodeNum(), + // mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); + + if (mp.from == nodeDB.getNodeNum()) { + + /* + * If SERIALPLUGIN_ECHO is true, then echo the packets that are sent out back to the TX + * of the serial interface. + */ + if (SERIALPLUGIN_ECHO) { + + // For some reason, we get the packet back twice when we send out of the radio. + // TODO: need to find out why. + if (lastRxID != mp.id) { + lastRxID = mp.id; + // DEBUG_MSG("* * Message came this device\n"); + // Serial2.println("* * Message came this device"); + Serial2.printf("%s", p.payload.bytes); + } + } + + } else { + // DEBUG_MSG("* * Message came from the mesh\n"); + // Serial2.println("* * Message came from the mesh"); + Serial2.printf("%s", p.payload.bytes); + } + +#else + DEBUG_MSG("Serial Plugin Disabled\n"); + +#endif + +#endif + + return true; // Let others look at this message also if they want +} diff --git a/src/plugins/SerialPlugin.h b/src/plugins/SerialPlugin.h new file mode 100644 index 00000000..c6d79f3e --- /dev/null +++ b/src/plugins/SerialPlugin.h @@ -0,0 +1,54 @@ +#pragma once + +#include "SinglePortPlugin.h" +#include "concurrency/OSThread.h" +#include "configuration.h" +#include +#include + +class SerialPlugin : private concurrency::OSThread +{ + bool firstTime = 1; + + public: + SerialPlugin(); + + protected: + virtual int32_t runOnce(); +}; + +extern SerialPlugin *serialPlugin; + +/* + * Radio interface for SerialPlugin + * + */ +class SerialPluginRadio : public SinglePortPlugin +{ + uint32_t lastRxID; + + public: + /* + TODO: Switch this to PortNum_SERIAL_APP once the change is able to be merged back here + from the main code. + */ + + SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + // SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {} + + /** + * Send our payload into the mesh + */ + void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + + protected: + virtual MeshPacket *allocReply(); + + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceived(const MeshPacket &mp); +}; + +extern SerialPluginRadio *serialPluginRadio; \ No newline at end of file