maintenance mode (experimental)
This commit is contained in:
parent
ad2c889889
commit
b1e08f0269
17
include/boot.h
Normal file
17
include/boot.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef BOOT_H
|
||||
#define BOOT_H
|
||||
|
||||
#include "globals.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include <Update.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WebServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
|
||||
void IRAM_ATTR exit_boot_menu(void);
|
||||
void start_boot_menu(void);
|
||||
|
||||
#endif // BOOT_H
|
@ -4,6 +4,6 @@
|
||||
#include <Arduino.h>
|
||||
#include <RokkitHash.h>
|
||||
|
||||
uint32_t IRAM_ATTR hash(const char *data, int len);
|
||||
uint32_t IRAM_ATTR myhash(const char *data, int len);
|
||||
|
||||
#endif
|
@ -20,5 +20,6 @@
|
||||
#include "lorawan.h"
|
||||
#include "timekeeper.h"
|
||||
#include "corona.h"
|
||||
#include "boot.h"
|
||||
|
||||
#endif
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "globals.h"
|
||||
#include "rcommand.h"
|
||||
#include "hash.h"
|
||||
#include <MQTT.h>
|
||||
#include <ETH.h>
|
||||
#include <mbedtls/base64.h>
|
||||
|
@ -13,13 +13,8 @@
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <BintrayClient.h>
|
||||
|
||||
#include <WiFiClient.h>
|
||||
#include <WebServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
|
||||
int do_ota_update();
|
||||
void start_ota_update();
|
||||
void start_maintenance();
|
||||
void ota_display(const uint8_t row, const std::string status,
|
||||
const std::string msg);
|
||||
void show_progress(unsigned long current, unsigned long size);
|
||||
|
145
src/boot.cpp
Normal file
145
src/boot.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
#include "boot.h"
|
||||
#include "reset.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
void IRAM_ATTR exit_boot_menu() {
|
||||
RTC_runmode = RUNMODE_NORMAL;
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
// start local web server with user interface for maintenance mode
|
||||
// used for manually uploading a firmware file via wifi
|
||||
|
||||
void start_boot_menu(void) {
|
||||
|
||||
uint8_t mac[6];
|
||||
char clientId[20];
|
||||
|
||||
// hash 6 byte MAC to 4 byte hash
|
||||
esp_eth_get_mac(mac);
|
||||
const uint32_t hashedmac = myhash((const char *)mac, 6);
|
||||
snprintf(clientId, 20, "paxcounter_%08x", hashedmac);
|
||||
|
||||
const char *host = clientId;
|
||||
const char *ssid = WIFI_SSID;
|
||||
const char *password = WIFI_PASS;
|
||||
|
||||
hw_timer_t *timer = NULL;
|
||||
timer = timerBegin(2, 80, true); // timer 2, div 80, countup
|
||||
timerAttachInterrupt(timer, &exit_boot_menu, true); // attach callback
|
||||
timerAlarmWrite(timer, BOOTDELAY * 1000000, false); // set time in us
|
||||
timerAlarmEnable(timer); // enable interrupt
|
||||
|
||||
WebServer server(80);
|
||||
|
||||
/*
|
||||
const char *serverIndex =
|
||||
"<form method='POST' action='/update' "
|
||||
"enctype='multipart/form-data'><input type='file' name='update'><input "
|
||||
"type='submit' value='Update'></form>";
|
||||
*/
|
||||
|
||||
const char *serverIndex =
|
||||
"<script "
|
||||
"src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/"
|
||||
"jquery.min.js'></script>"
|
||||
"<form method='POST' action='#' enctype='multipart/form-data' "
|
||||
"id='upload_form'>"
|
||||
"<input type='file' name='update'>"
|
||||
"<input type='submit' value='Update'>"
|
||||
"</form>"
|
||||
"<div id='prg'>progress: 0%</div>"
|
||||
"<script>"
|
||||
"$('form').submit(function(e){"
|
||||
"e.preventDefault();"
|
||||
"var form = $('#upload_form')[0];"
|
||||
"var data = new FormData(form);"
|
||||
" $.ajax({"
|
||||
"url: '/update',"
|
||||
"type: 'POST',"
|
||||
"data: data,"
|
||||
"contentType: false,"
|
||||
"processData:false,"
|
||||
"xhr: function() {"
|
||||
"var xhr = new window.XMLHttpRequest();"
|
||||
"xhr.upload.addEventListener('progress', function(evt) {"
|
||||
"if (evt.lengthComputable) {"
|
||||
"var per = evt.loaded / evt.total;"
|
||||
"$('#prg').html('progress: ' + Math.round(per*100) + '%');"
|
||||
"}"
|
||||
"}, false);"
|
||||
"return xhr;"
|
||||
"},"
|
||||
"success:function(d, s) {"
|
||||
"console.log('success!')"
|
||||
"},"
|
||||
"error: function (a, b, c) {"
|
||||
"}"
|
||||
"});"
|
||||
"});"
|
||||
"</script>";
|
||||
|
||||
// Connect to WiFi network
|
||||
// WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
}
|
||||
|
||||
MDNS.begin(host);
|
||||
|
||||
server.on("/", HTTP_GET, [&server, &serverIndex]() {
|
||||
server.sendHeader("Connection", "close");
|
||||
server.send(200, "text/html", serverIndex);
|
||||
});
|
||||
|
||||
// handling uploading firmware file
|
||||
server.on(
|
||||
"/update", HTTP_POST,
|
||||
[&server]() {
|
||||
server.sendHeader("Connection", "close");
|
||||
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
|
||||
},
|
||||
[&server, &timer]() {
|
||||
HTTPUpload &upload = server.upload();
|
||||
if (upload.status == UPLOAD_FILE_START) {
|
||||
timerAlarmWrite(timer, BOOTTIMEOUT * 1000000, false);
|
||||
ESP_LOGI(TAG, "Update: %s\n", upload.filename.c_str());
|
||||
if (!Update.begin(
|
||||
UPDATE_SIZE_UNKNOWN)) { // start with max available size
|
||||
ESP_LOGE(TAG, "Error: %s", Update.errorString());
|
||||
}
|
||||
} else if (upload.status == UPLOAD_FILE_WRITE) {
|
||||
// flashing firmware to ESP
|
||||
if (Update.write(upload.buf, upload.currentSize) !=
|
||||
upload.currentSize) {
|
||||
ESP_LOGE(TAG, "Error: %s", Update.errorString());
|
||||
}
|
||||
} else if (upload.status == UPLOAD_FILE_END) {
|
||||
if (Update.end(
|
||||
true)) { // true to set the size to the current progress
|
||||
ESP_LOGI(TAG, "Update finished, %u bytes written",
|
||||
upload.totalSize);
|
||||
WiFi.disconnect(true, true);
|
||||
do_reset(false); // coldstart
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Update failed");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server.begin();
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
ESP_LOGI(TAG, "WiFi connected to '%s', open http://%s in your browser",
|
||||
WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());
|
||||
|
||||
while (1) {
|
||||
server.handleClient();
|
||||
timerWrite(timer, 0); // reset timer (feed watchdog)
|
||||
delay(1);
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ void doHousekeeping() {
|
||||
|
||||
// check if update or maintenance mode trigger switch was set by rcommand
|
||||
if ((RTC_runmode == RUNMODE_UPDATE) || (RTC_runmode == RUNMODE_MAINTENANCE))
|
||||
do_reset(true);
|
||||
do_reset(true); // warmstart
|
||||
|
||||
// heap and task storage debugging
|
||||
ESP_LOGD(TAG, "Heap: Free:%d, Min:%d, Size:%d, Alloc:%d, StackHWM:%d",
|
||||
|
@ -40,6 +40,6 @@
|
||||
#undef ROKKIT_ENABLE_8BIT_OPTIMIZATIONS
|
||||
#endif
|
||||
|
||||
uint32_t IRAM_ATTR hash(const char *data, int len) {
|
||||
uint32_t IRAM_ATTR myhash(const char *data, int len) {
|
||||
return rokkit(data, len);
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) {
|
||||
// hashed 4 byte MAC
|
||||
// to save RAM, we use only lower 2 bytes of hash, since collisions don't
|
||||
// matter in our use case
|
||||
hashedmac = hash((const char *)&saltedmac, 4);
|
||||
hashedmac = myhash((const char *)&saltedmac, 4);
|
||||
|
||||
auto newmac = macs.insert(hashedmac); // add hashed MAC, if new unique
|
||||
bool added =
|
||||
|
12
src/main.cpp
12
src/main.cpp
@ -51,6 +51,7 @@ So don't do it if you do not own a digital oscilloscope.
|
||||
-------------------------------------------------------------------------------
|
||||
0 displayIRQ -> display refresh -> 40ms (DISPLAYREFRESH_MS)
|
||||
1 ppsIRQ -> pps clock irq -> 1sec
|
||||
2 watchdog -> used in boot.cpp
|
||||
3 MatrixDisplayIRQ -> matrix mux cycle -> 0,5ms (MATRIX_DISPLAY_SCAN_US)
|
||||
|
||||
|
||||
@ -290,9 +291,16 @@ void setup() {
|
||||
start_ota_update();
|
||||
#endif
|
||||
|
||||
// start local webserver if maintenance trigger switch is set
|
||||
#if (BOOTMENU)
|
||||
// start local webserver after device powers up or on rcommand request
|
||||
if ((RTC_runmode == RUNMODE_POWERCYCLE) ||
|
||||
(RTC_runmode == RUNMODE_MAINTENANCE))
|
||||
start_boot_menu();
|
||||
#else
|
||||
// start local webserver on rcommand request only
|
||||
if (RTC_runmode == RUNMODE_MAINTENANCE)
|
||||
start_maintenance();
|
||||
start_boot_menu();
|
||||
#endif
|
||||
|
||||
// start mac processing task
|
||||
ESP_LOGI(TAG, "Starting MAC processor...");
|
||||
|
@ -48,7 +48,7 @@ int mqtt_connect(const char *my_host, const uint16_t my_port) {
|
||||
|
||||
// hash 6 byte MAC to 4 byte hash
|
||||
esp_eth_get_mac(mac);
|
||||
const uint32_t hashedmac = hash((const char *)mac, 6);
|
||||
const uint32_t hashedmac = myhash((const char *)mac, 6);
|
||||
snprintf(clientId, 20, "paxcounter_%08x", hashedmac);
|
||||
|
||||
ESP_LOGI(TAG, "MQTT name is %s", MQTT_CLIENTNAME);
|
||||
|
121
src/ota.cpp
121
src/ota.cpp
@ -330,125 +330,4 @@ void show_progress(unsigned long current, unsigned long size) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// start local web server with user interface for maintenance mode
|
||||
// used for manually uploading a firmware file via wifi
|
||||
|
||||
void start_maintenance(void) {
|
||||
|
||||
// code snippets taken from
|
||||
// github.com/espressif/arduino-esp32/blob/master/libraries/ArduinoOTA/examples/OTAWebUpdater/OTAWebUpdater.ino
|
||||
|
||||
const char *host = "paxcounter";
|
||||
const char *ssid = WIFI_SSID;
|
||||
const char *password = WIFI_PASS;
|
||||
|
||||
WebServer server(80);
|
||||
|
||||
const char *serverIndex =
|
||||
"<script "
|
||||
"src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/"
|
||||
"jquery.min.js'></script>"
|
||||
"<form method='POST' action='#' enctype='multipart/form-data' "
|
||||
"id='upload_form'>"
|
||||
"<input type='file' name='update'>"
|
||||
"<input type='submit' value='Update'>"
|
||||
"</form>"
|
||||
"<div id='prg'>progress: 0%</div>"
|
||||
"<script>"
|
||||
"$('form').submit(function(e){"
|
||||
"e.preventDefault();"
|
||||
"var form = $('#upload_form')[0];"
|
||||
"var data = new FormData(form);"
|
||||
" $.ajax({"
|
||||
"url: '/update',"
|
||||
"type: 'POST',"
|
||||
"data: data,"
|
||||
"contentType: false,"
|
||||
"processData:false,"
|
||||
"xhr: function() {"
|
||||
"var xhr = new window.XMLHttpRequest();"
|
||||
"xhr.upload.addEventListener('progress', function(evt) {"
|
||||
"if (evt.lengthComputable) {"
|
||||
"var per = evt.loaded / evt.total;"
|
||||
"$('#prg').html('progress: ' + Math.round(per*100) + '%');"
|
||||
"}"
|
||||
"}, false);"
|
||||
"return xhr;"
|
||||
"},"
|
||||
"success:function(d, s) {"
|
||||
"console.log('success!')"
|
||||
"},"
|
||||
"error: function (a, b, c) {"
|
||||
"}"
|
||||
"});"
|
||||
"});"
|
||||
"</script>";
|
||||
|
||||
// Connect to WiFi network
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
delay(500);
|
||||
|
||||
ESP_LOGI(TAG, "Connected to %s", ssid);
|
||||
ESP_LOGI(TAG, "Open http://%s.local in your browser", host);
|
||||
|
||||
// use mdns for host name resolution
|
||||
if (!MDNS.begin(host)) {
|
||||
ESP_LOGI(TAG, "Error setting up mDNS responder!");
|
||||
delay(3000);
|
||||
do_reset(false);
|
||||
}
|
||||
|
||||
server.on("/", HTTP_GET, [&server, &serverIndex]() {
|
||||
server.sendHeader("Connection", "close");
|
||||
server.send(200, "text/html", serverIndex);
|
||||
});
|
||||
|
||||
// handling uploading firmware file
|
||||
server.on(
|
||||
"/update", HTTP_POST,
|
||||
[&server]() {
|
||||
server.sendHeader("Connection", "close");
|
||||
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
|
||||
do_reset(false);
|
||||
},
|
||||
[&server]() {
|
||||
HTTPUpload &upload = server.upload();
|
||||
if (upload.status == UPLOAD_FILE_START) {
|
||||
ESP_LOGI(TAG, "Update: %s\n", upload.filename.c_str());
|
||||
if (!Update.begin(
|
||||
UPDATE_SIZE_UNKNOWN)) { // start with max available size
|
||||
ESP_LOGE(TAG, "Error: %s", Update.errorString());
|
||||
}
|
||||
} else if (upload.status == UPLOAD_FILE_WRITE) {
|
||||
// flashing firmware to ESP
|
||||
if (Update.write(upload.buf, upload.currentSize) !=
|
||||
upload.currentSize) {
|
||||
ESP_LOGE(TAG, "Error: %s", Update.errorString());
|
||||
}
|
||||
} else if (upload.status == UPLOAD_FILE_END) {
|
||||
if (Update.end(
|
||||
true)) { // true to set the size to the current progress
|
||||
ESP_LOGI(TAG, "Update finished, %u bytes written",
|
||||
upload.totalSize);
|
||||
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Update failed");
|
||||
}
|
||||
delay(3000);
|
||||
do_reset(false);
|
||||
}
|
||||
});
|
||||
|
||||
server.begin();
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
|
||||
while (1) {
|
||||
server.handleClient();
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USE_OTA
|
@ -32,11 +32,11 @@ void set_reset(uint8_t val[]) {
|
||||
do_reset(true);
|
||||
break;
|
||||
case 8: // reset and start local web server for manual software update
|
||||
ESP_LOGI(TAG, "Remote command: software update via user interface");
|
||||
ESP_LOGI(TAG, "Remote command: reboot to maintenance mode");
|
||||
RTC_runmode = RUNMODE_MAINTENANCE;
|
||||
break;
|
||||
case 9: // reset and ask OTA server via Wifi for automated software update
|
||||
ESP_LOGI(TAG, "Remote command: software update via Wifi");
|
||||
ESP_LOGI(TAG, "Remote command: reboot to ota update mode");
|
||||
#if (USE_OTA)
|
||||
// check power status before scheduling ota update
|
||||
if (batt_sufficient())
|
||||
|
@ -14,7 +14,8 @@ RTC_DATA_ATTR struct timeval RTC_sleep_start_time;
|
||||
RTC_DATA_ATTR unsigned long long RTC_millis = 0;
|
||||
timeval sleep_stop_time;
|
||||
|
||||
const char *runmode[6] = {"powercycle", "normal", "wakeup", "update", "sleep", "maintenance"};
|
||||
const char *runmode[6] = {"powercycle", "normal", "wakeup",
|
||||
"update", "sleep", "maintenance"};
|
||||
|
||||
void do_reset(bool warmstart) {
|
||||
if (warmstart) {
|
||||
@ -45,7 +46,8 @@ void do_after_reset(void) {
|
||||
break;
|
||||
|
||||
case SW_CPU_RESET: // 0x0c Software reset CPU
|
||||
// keep previous runmode (could be RUNMODE_UPDATE)
|
||||
// keep previous runmode
|
||||
// (i.e. RUNMODE_UPDATE or RUNMODE_MAINTENANCE)
|
||||
break;
|
||||
|
||||
case DEEPSLEEP_RESET: // 0x05 Deep Sleep reset digital core
|
||||
|
Loading…
Reference in New Issue
Block a user