diff --git a/bin/build-all.sh b/bin/build-all.sh
index c27760c4..caa7c59a 100755
--- a/bin/build-all.sh
+++ b/bin/build-all.sh
@@ -14,7 +14,7 @@ BOARDS_ESP32="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
BOARDS_NRF52="lora-relay-v1"
-NUM_JOBS=2
+NUM_JOBS=2 || true
OUTDIR=release/latest
diff --git a/docs/radio-settings.md b/docs/radio-settings.md
index 2bf9ccda..7af9d79e 100644
--- a/docs/radio-settings.md
+++ b/docs/radio-settings.md
@@ -28,3 +28,14 @@ The maximum output power for North America is +30 dBm ERP.
The band is from 902 to 928 MHz. It mentions channel number and its respective channel frequency. All the 13 channels are separated by 2.16 MHz with respect to the adjacent channels.
Channel zero starts at 903.08 MHz center frequency.
+
+## Data-rates
+
+Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices:
+
+| Channel setting | Data-rate |
+|----------------------------|----------------------|
+| Short range (but fast) | 21.875 kbps |
+| Medium range (but fast) | 5.469 kbps |
+| Long range (but slower) | 0.275 kbps |
+| Very long range (but slow) | 0.183 kbps (default) |
diff --git a/platformio.ini b/platformio.ini
index 149d2d78..9e3b123d 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -185,7 +185,7 @@ build_type = debug ; I'm debugging with ICE a lot now
build_flags =
${arduino_base.build_flags} -Wno-unused-variable
-Isrc/nrf52
- -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3
+ -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
;-DCFG_DEBUG=3
src_filter =
${arduino_base.src_filter} - - - -
diff --git a/proto b/proto
index 4c62d8e5..855da870 160000
--- a/proto
+++ b/proto
@@ -1 +1 @@
-Subproject commit 4c62d8e53696074d7c368518afd9d564df374fcf
+Subproject commit 855da8701edbb19818069ad8545d5b9f030bb33f
diff --git a/sdk-nrfxlib b/sdk-nrfxlib
index 17e84535..e6e02cb8 160000
--- a/sdk-nrfxlib
+++ b/sdk-nrfxlib
@@ -1 +1 @@
-Subproject commit 17e8453553d4cfc21ab87c53c9627f0cf1216429
+Subproject commit e6e02cb83d238fae2f54f084858bd5e49a31afa1
diff --git a/src/Power.cpp b/src/Power.cpp
index 82e88f8c..f4aa700a 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -1,4 +1,5 @@
#include "power.h"
+#include "NodeDB.h"
#include "PowerFSM.h"
#include "main.h"
#include "sleep.h"
@@ -268,9 +269,42 @@ bool Power::axp192Init()
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
- //axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA); // actual limit (in HW) on the tbeam is 450mA
- axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA); // There's no HW limit on the tbeam. Setting to 450mz to be a good neighbor on the usb bus.
-
+ if (radioConfig.preferences.charge_current == ChargeCurrent_MAUnset) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA100) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_100MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA190) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_190MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA280) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_280MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA360) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_360MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA450) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA550) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_550MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA630) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_630MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA700) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_700MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA780) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_780MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA880) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_880MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA960) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_960MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1000) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1000MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1080) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1080MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1160) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1160MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1240) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1240MA);
+ } else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1320) {
+ axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA);
+ }
+
#if 0
// Not connected
diff --git a/src/main.cpp b/src/main.cpp
index b63c193a..aa7b191d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -303,17 +303,20 @@ void setup()
digitalWrite(RESET_OLED, 1);
#endif
+#ifdef BUTTON_PIN
+#ifndef NO_ESP32
// If BUTTON_PIN is held down during the startup process,
// force the device to go into a SoftAP mode.
bool forceSoftAP = 0;
-#ifdef BUTTON_PIN
-#ifndef NO_ESP32
pinMode(BUTTON_PIN, INPUT);
+#ifdef BUTTON_NEED_PULLUP
+ gpio_pullup_en((gpio_num_t)BUTTON_PIN);
+#endif
// BUTTON_PIN is pulled high by a 12k resistor.
if (!digitalRead(BUTTON_PIN)) {
forceSoftAP = 1;
- DEBUG_MSG("-------------------- Setting forceSoftAP = 1\n");
+ DEBUG_MSG("Setting forceSoftAP = 1\n");
}
#endif
@@ -513,7 +516,6 @@ void setup()
}
#endif
-
#ifndef NO_ESP32
// Initialize Wifi
initWifi(forceSoftAP);
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index dc13bc42..42ce71ea 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -7,6 +7,7 @@
#include "CryptoEngine.h"
#include "FSCommon.h"
#include "GPS.h"
+#include "main.h"
#include "MeshRadio.h"
#include "NodeDB.h"
#include "PacketHistory.h"
@@ -583,8 +584,14 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
/// Record an error that should be reported via analytics
void recordCriticalError(CriticalErrorCode code, uint32_t address)
{
+ // Print error to screen and serial port
+ String lcd = String("Critical error ") + code + "!\n";
+ screen->print(lcd.c_str());
DEBUG_MSG("NOTE! Recording critical error %d, address=%x\n", code, address);
+
+ // Record error to DB
myNodeInfo.error_code = code;
myNodeInfo.error_address = address;
myNodeInfo.error_count++;
+
}
diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp
index 0266614a..f2fafef7 100644
--- a/src/mesh/RadioLibInterface.cpp
+++ b/src/mesh/RadioLibInterface.cpp
@@ -3,6 +3,7 @@
#include "NodeDB.h"
#include "SPILock.h"
#include "mesh-pb-constants.h"
+#include "error.h"
#include
#include
#include
@@ -67,9 +68,20 @@ bool RadioLibInterface::canSendImmediately()
bool busyTx = sendingPacket != NULL;
bool busyRx = isReceiving && isActivelyReceiving();
+
if (busyTx || busyRx) {
if (busyTx)
DEBUG_MSG("Can not send yet, busyTx\n");
+ // If we've been trying to send the same packet more than one minute and we haven't gotten a
+ // TX IRQ from the radio, the radio is probably broken.
+ if (busyTx && (millis() - lastTxStart > 60000)){
+ DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
+ recordCriticalError(CriticalErrorCode_TransmitFailed);
+#ifndef NO_ESP32
+ if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot
+ ESP.restart();
+#endif
+ }
if (busyRx)
DEBUG_MSG("Can not send yet, busyRx\n");
return false;
diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h
index 39f39275..c3e55666 100644
--- a/src/mesh/generated/deviceonly.pb.h
+++ b/src/mesh/generated/deviceonly.pb.h
@@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg;
#define DeviceState_fields &DeviceState_msg
/* Maximum encoded size of messages (where known) */
-#define DeviceState_size 6176
+#define DeviceState_size 6206
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/mesh.pb.c b/src/mesh/generated/mesh.pb.c
index 8f976cac..3bc2b080 100644
--- a/src/mesh/generated/mesh.pb.c
+++ b/src/mesh/generated/mesh.pb.c
@@ -57,3 +57,4 @@ PB_BIND(ToRadio, ToRadio, 2)
+
diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h
index 0962effa..50ae14a6 100644
--- a/src/mesh/generated/mesh.pb.h
+++ b/src/mesh/generated/mesh.pb.h
@@ -35,6 +35,26 @@ typedef enum _RegionCode {
RegionCode_TW = 8
} RegionCode;
+typedef enum _ChargeCurrent {
+ ChargeCurrent_MAUnset = 0,
+ ChargeCurrent_MA100 = 1,
+ ChargeCurrent_MA190 = 2,
+ ChargeCurrent_MA280 = 3,
+ ChargeCurrent_MA360 = 4,
+ ChargeCurrent_MA450 = 5,
+ ChargeCurrent_MA550 = 6,
+ ChargeCurrent_MA630 = 7,
+ ChargeCurrent_MA700 = 8,
+ ChargeCurrent_MA780 = 9,
+ ChargeCurrent_MA880 = 10,
+ ChargeCurrent_MA960 = 11,
+ ChargeCurrent_MA1000 = 12,
+ ChargeCurrent_MA1080 = 13,
+ ChargeCurrent_MA1160 = 14,
+ ChargeCurrent_MA1240 = 15,
+ ChargeCurrent_MA1320 = 16
+} ChargeCurrent;
+
typedef enum _GpsOperation {
GpsOperation_GpsOpUnset = 0,
GpsOperation_GpsOpMobile = 2,
@@ -56,7 +76,8 @@ typedef enum _CriticalErrorCode {
CriticalErrorCode_Unspecified = 4,
CriticalErrorCode_UBloxInitFailed = 5,
CriticalErrorCode_NoAXP192 = 6,
- CriticalErrorCode_InvalidRadioSetting = 7
+ CriticalErrorCode_InvalidRadioSetting = 7,
+ CriticalErrorCode_TransmitFailed = 8
} CriticalErrorCode;
typedef enum _ChannelSettings_ModemConfig {
@@ -145,6 +166,7 @@ typedef struct _RadioConfig_UserPreferences {
char wifi_password[64];
bool wifi_ap_mode;
RegionCode region;
+ ChargeCurrent charge_current;
LocationSharing location_share;
GpsOperation gps_operation;
uint32_t gps_update_interval;
@@ -156,6 +178,11 @@ typedef struct _RadioConfig_UserPreferences {
bool debug_log_enabled;
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
+ bool serialplugin_enabled;
+ bool serialplugin_echo;
+ uint32_t serialplugin_rxd;
+ uint32_t serialplugin_txd;
+ uint32_t serialplugin_timeout;
} RadioConfig_UserPreferences;
typedef struct _RouteDiscovery {
@@ -265,6 +292,10 @@ typedef struct _ToRadio {
#define _RegionCode_MAX RegionCode_TW
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1))
+#define _ChargeCurrent_MIN ChargeCurrent_MAUnset
+#define _ChargeCurrent_MAX ChargeCurrent_MA1320
+#define _ChargeCurrent_ARRAYSIZE ((ChargeCurrent)(ChargeCurrent_MA1320+1))
+
#define _GpsOperation_MIN GpsOperation_GpsOpUnset
#define _GpsOperation_MAX GpsOperation_GpsOpDisabled
#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1))
@@ -299,7 +330,7 @@ extern "C" {
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0}
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
-#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
+#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 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, 0}
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
@@ -313,7 +344,7 @@ extern "C" {
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
-#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
+#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 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, 0}
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
@@ -371,6 +402,7 @@ extern "C" {
#define RadioConfig_UserPreferences_wifi_password_tag 13
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
#define RadioConfig_UserPreferences_region_tag 15
+#define RadioConfig_UserPreferences_charge_current_tag 16
#define RadioConfig_UserPreferences_location_share_tag 32
#define RadioConfig_UserPreferences_gps_operation_tag 33
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
@@ -381,6 +413,11 @@ extern "C" {
#define RadioConfig_UserPreferences_factory_reset_tag 100
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
+#define RadioConfig_UserPreferences_serialplugin_enabled_tag 120
+#define RadioConfig_UserPreferences_serialplugin_echo_tag 121
+#define RadioConfig_UserPreferences_serialplugin_rxd_tag 122
+#define RadioConfig_UserPreferences_serialplugin_txd_tag 123
+#define RadioConfig_UserPreferences_serialplugin_timeout_tag 124
#define RouteDiscovery_route_tag 2
#define User_id_tag 1
#define User_long_name_tag 2
@@ -533,6 +570,7 @@ X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \
X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
X(a, STATIC, SINGULAR, UENUM, region, 15) \
+X(a, STATIC, SINGULAR, UENUM, charge_current, 16) \
X(a, STATIC, SINGULAR, UENUM, location_share, 32) \
X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
@@ -542,7 +580,12 @@ X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
-X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
+X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \
+X(a, STATIC, SINGULAR, BOOL, serialplugin_enabled, 120) \
+X(a, STATIC, SINGULAR, BOOL, serialplugin_echo, 121) \
+X(a, STATIC, SINGULAR, UINT32, serialplugin_rxd, 122) \
+X(a, STATIC, SINGULAR, UINT32, serialplugin_txd, 123) \
+X(a, STATIC, SINGULAR, UINT32, serialplugin_timeout, 124)
#define RadioConfig_UserPreferences_CALLBACK NULL
#define RadioConfig_UserPreferences_DEFAULT NULL
@@ -654,13 +697,13 @@ extern const pb_msgdesc_t ToRadio_msg;
#define SubPacket_size 275
#define MeshPacket_size 320
#define ChannelSettings_size 95
-#define RadioConfig_size 319
-#define RadioConfig_UserPreferences_size 219
+#define RadioConfig_size 349
+#define RadioConfig_UserPreferences_size 249
#define NodeInfo_size 132
#define MyNodeInfo_size 106
#define LogRecord_size 81
-#define FromRadio_size 329
-#define ToRadio_size 323
+#define FromRadio_size 358
+#define ToRadio_size 353
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h
index bef19c12..91c988fd 100644
--- a/src/mesh/generated/portnums.pb.h
+++ b/src/mesh/generated/portnums.pb.h
@@ -18,13 +18,15 @@ typedef enum _PortNum {
PortNum_NODEINFO_APP = 4,
PortNum_REPLY_APP = 32,
PortNum_IP_TUNNEL_APP = 33,
- PortNum_PRIVATE_APP = 256
+ PortNum_SERIAL_APP = 64,
+ PortNum_PRIVATE_APP = 256,
+ PortNum_ATAK_FORWARDER = 257
} PortNum;
/* Helper constants for enums */
#define _PortNum_MIN PortNum_UNKNOWN_APP
-#define _PortNum_MAX PortNum_PRIVATE_APP
-#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_PRIVATE_APP+1))
+#define _PortNum_MAX PortNum_ATAK_FORWARDER
+#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_ATAK_FORWARDER+1))
#ifdef __cplusplus
diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp
new file mode 100644
index 00000000..5f79702f
--- /dev/null
+++ b/src/mesh/http/ContentHandler.cpp
@@ -0,0 +1,1073 @@
+#include "NodeDB.h"
+#include "PowerFSM.h"
+#include "airtime.h"
+#include "main.h"
+#include "mesh/http/ContentHelper.h"
+#include "mesh/http/ContentStatic.h"
+#include "mesh/http/WiFiAPClient.h"
+#include "power.h"
+#include "sleep.h"
+#include
+#include
+#include
+#include
+
+#ifndef NO_ESP32
+#include "esp_task_wdt.h"
+#endif
+
+/*
+ Including the esp32_https_server library will trigger a compile time error. I've
+ tracked it down to a reoccurrance of this bug:
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824
+ The work around is described here:
+ https://forums.xilinx.com/t5/Embedded-Development-Tools/Error-with-Standard-Libaries-in-Zynq/td-p/450032
+
+ Long story short is we need "#undef str" before including the esp32_https_server.
+ - Jm Casler (jm@casler.org) Oct 2020
+*/
+#undef str
+
+// Includes for the https server
+// https://github.com/fhessel/esp32_https_server
+#include
+#include
+#include
+#include
+#include
+
+// The HTTPS Server comes in a separate namespace. For easier use, include it here.
+using namespace httpsserver;
+
+#include "mesh/http/ContentHandler.h"
+
+// We need to specify some content-type mapping, so the resources get delivered with the
+// right content type and are displayed correctly in the browser
+char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"},
+ {".js", "text/javascript"}, {".png", "image/png"},
+ {".jpg", "image/jpg"}, {".gz", "application/gzip"},
+ {".gif", "image/gif"}, {".json", "application/json"},
+ {".css", "text/css"}, {".ico", "image/vnd.microsoft.icon"},
+ {".svg", "image/svg+xml"}, {"", ""}};
+
+// Our API to handle messages to and from the radio.
+HttpAPI webAPI;
+
+uint32_t numberOfRequests = 0;
+uint32_t timeSpeedUp = 0;
+
+uint32_t getTimeSpeedUp()
+{
+ return timeSpeedUp;
+}
+
+void setTimeSpeedUp()
+{
+ timeSpeedUp = millis();
+}
+
+void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
+{
+
+ // 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 *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);
+ ResourceNode *nodeStaticBrowse = new ResourceNode("/static", "GET", &handleStaticBrowse);
+ ResourceNode *nodeStaticPOST = new ResourceNode("/static", "POST", &handleStaticPost);
+ ResourceNode *nodeStatic = new ResourceNode("/static/*", "GET", &handleStatic);
+ ResourceNode *nodeRestart = new ResourceNode("/restart", "POST", &handleRestart);
+ ResourceNode *node404 = new ResourceNode("", "GET", &handle404);
+ ResourceNode *nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload);
+ ResourceNode *nodeJsonScanNetworks = new ResourceNode("/json/scanNetworks", "GET", &handleScanNetworks);
+ ResourceNode *nodeJsonBlinkLED = new ResourceNode("/json/blink", "POST", &handleBlinkLED);
+ ResourceNode *nodeJsonReport = new ResourceNode("/json/report", "GET", &handleReport);
+ ResourceNode *nodeJsonSpiffsBrowseStatic = new ResourceNode("/json/spiffs/browse/static", "GET", &handleSpiffsBrowseStatic);
+ ResourceNode *nodeJsonDelete = new ResourceNode("/json/spiffs/delete/static", "DELETE", &handleSpiffsDeleteStatic);
+
+ // Secure nodes
+ secureServer->registerNode(nodeAPIv1ToRadioOptions);
+ secureServer->registerNode(nodeAPIv1ToRadio);
+ secureServer->registerNode(nodeAPIv1FromRadio);
+ secureServer->registerNode(nodeHotspot);
+ secureServer->registerNode(nodeFavicon);
+ secureServer->registerNode(nodeRoot);
+ secureServer->registerNode(nodeStaticBrowse);
+ secureServer->registerNode(nodeStaticPOST);
+ secureServer->registerNode(nodeStatic);
+ secureServer->registerNode(nodeRestart);
+ secureServer->registerNode(nodeFormUpload);
+ secureServer->registerNode(nodeJsonScanNetworks);
+ secureServer->registerNode(nodeJsonBlinkLED);
+ secureServer->registerNode(nodeJsonSpiffsBrowseStatic);
+ secureServer->registerNode(nodeJsonDelete);
+ secureServer->registerNode(nodeJsonReport);
+ secureServer->setDefaultNode(node404);
+
+ secureServer->addMiddleware(&middlewareSpeedUp240);
+
+ // Insecure nodes
+ insecureServer->registerNode(nodeAPIv1ToRadioOptions);
+ insecureServer->registerNode(nodeAPIv1ToRadio);
+ insecureServer->registerNode(nodeAPIv1FromRadio);
+ insecureServer->registerNode(nodeHotspot);
+ insecureServer->registerNode(nodeFavicon);
+ insecureServer->registerNode(nodeRoot);
+ insecureServer->registerNode(nodeStaticBrowse);
+ insecureServer->registerNode(nodeStaticPOST);
+ insecureServer->registerNode(nodeStatic);
+ insecureServer->registerNode(nodeRestart);
+ insecureServer->registerNode(nodeFormUpload);
+ insecureServer->registerNode(nodeJsonScanNetworks);
+ insecureServer->registerNode(nodeJsonBlinkLED);
+ insecureServer->registerNode(nodeJsonSpiffsBrowseStatic);
+ insecureServer->registerNode(nodeJsonDelete);
+ insecureServer->registerNode(nodeJsonReport);
+ insecureServer->setDefaultNode(node404);
+
+ insecureServer->addMiddleware(&middlewareSpeedUp160);
+}
+
+void middlewareSpeedUp240(HTTPRequest *req, HTTPResponse *res, std::function next)
+{
+ // We want to print the response status, so we need to call next() first.
+ next();
+
+ // Phone (or other device) has contacted us over WiFi. Keep the radio turned on.
+ // TODO: This should go into its own middleware layer separate from the speedup.
+ powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
+
+ setCpuFrequencyMhz(240);
+ setTimeSpeedUp();
+
+ numberOfRequests++;
+}
+
+void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::function next)
+{
+ // We want to print the response status, so we need to call next() first.
+ next();
+
+ // Phone (or other device) has contacted us over WiFi. Keep the radio turned on.
+ // TODO: This should go into its own middleware layer separate from the speedup.
+ powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
+
+ // If the frequency is 240mhz, we have recently gotten a HTTPS request.
+ // In that case, leave the frequency where it is and just update the
+ // countdown timer (timeSpeedUp).
+ if (getCpuFrequencyMhz() != 240) {
+ setCpuFrequencyMhz(160);
+ }
+ setTimeSpeedUp();
+
+ numberOfRequests++;
+}
+
+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", "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 handleFavicon(HTTPRequest *req, HTTPResponse *res)
+{
+ // Set Content-Type
+ res->setHeader("Content-Type", "image/vnd.microsoft.icon");
+ // Write data from header file
+ res->write(FAVICON_DATA, FAVICON_LENGTH);
+}
+
+void handleStaticPost(HTTPRequest *req, HTTPResponse *res)
+{
+ // Assume POST request. Contains submitted data.
+ res->println("File Edited
File Edited
");
+
+ // The form is submitted with the x-www-form-urlencoded content type, so we need the
+ // HTTPURLEncodedBodyParser to read the fields.
+ // Note that the content of the file's content comes from a