Merge pull request #42 from mc-hamster/osthread

Moving web server and airtime to osthread model. Moved web server to mesh/wifi
This commit is contained in:
Jm Casler 2021-01-08 22:29:45 -08:00 committed by GitHub
commit 4fd243a6e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 274 additions and 197 deletions

2
proto

@ -1 +1 @@
Subproject commit dfe7bc1217a00c23eecb9dfcf1d56fe95ebddc3b
Subproject commit 75078afe43934f4ce15ef86ebc6950658a170145

View File

@ -3,6 +3,8 @@
#define periodsToLog 48
AirTime *airTime;
// 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.
@ -11,25 +13,31 @@ 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];
uint16_t periodTX[periodsToLog]; // AirTime transmitted
uint16_t periodRX[periodsToLog]; // AirTime received and repeated (Only valid mesh packets)
uint16_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)
{
// DEBUG_MSG("Packet - logAirtime()\n");
if (reportType == TX_LOG) {
DEBUG_MSG("AirTime - Packet transmitted : %us %ums\n", (uint32_t)round((float)airtime_ms / (float)1000), airtime_ms);
airtimes.periodTX[0] = airtimes.periodTX[0] + round(airtime_ms / 1000);
} else if (reportType == RX_LOG) {
DEBUG_MSG("AirTime - Packet received : %us %ums\n", (uint32_t)round((float)airtime_ms / (float)1000), airtime_ms);
airtimes.periodRX[0] = airtimes.periodRX[0] + round(airtime_ms / 1000);
} else if (reportType == RX_ALL_LOG) {
DEBUG_MSG("AirTime - Packet received (noise?) : %us %ums\n", (uint32_t)round((float)airtime_ms / (float)1000), airtime_ms);
airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + round(airtime_ms / 1000);
} else {
// Unknown report type
DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n");
}
}
@ -38,29 +46,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)
{
// currentHourIndexReset();
if (reportType == TX_LOG) {
return airtimes.periodTX;
@ -86,3 +92,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);
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "concurrency/OSThread.h"
#include "configuration.h"
#include <Arduino.h>
#include <functional>
@ -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,7 +27,7 @@ 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();
@ -35,4 +36,19 @@ uint32_t getSecondsSinceBoot();
uint16_t *airtimeReport(reportTypes reportType);
uint32_t getSecondsPerPeriod();
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;

View File

@ -31,7 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graphics/images.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "meshwifi/meshwifi.h"
#include "mesh/wifi/WiFiAPClient.h"
#include "plugins/TextMessagePlugin.h"
#include "target_specific.h"
#include "utils.h"

View File

@ -19,10 +19,10 @@
#include "concurrency/Periodic.h"
#include "graphics/Screen.h"
#include "main.h"
#include "meshwifi/meshhttp.h"
#include "meshwifi/meshwifi.h"
#include "sleep.h"
#include "mesh/wifi/WebServer.h"
#include "mesh/wifi/WiFiAPClient.h"
#include "plugins/Plugins.h"
#include "sleep.h"
#include "target_specific.h"
#include <OneButton.h>
#include <Wire.h>
@ -516,6 +516,12 @@ void setup()
// Initialize Wifi
initWifi(forceSoftAP);
// Start web server thread.
webServerThread = new WebServerThread();
// Start airtime logger thread.
airTime = new AirTime();
if (!rIf)
recordCriticalError(CriticalErrorCode_NoRadio);
else
@ -576,7 +582,7 @@ void loop()
#endif
// TODO: This should go into a thread handled by FreeRTOS.
handleWebResponse();
// handleWebResponse();
service.loop();
@ -589,7 +595,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();
}

View File

@ -16,7 +16,7 @@
#include "configuration.h"
#include "error.h"
#include "mesh-pb-constants.h"
#include "meshwifi/meshwifi.h"
#include "mesh/wifi/WiFiAPClient.h"
#include <pb_decode.h>
#include <pb_encode.h>

View File

@ -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);
}

View File

@ -0,0 +1,14 @@
#include "mesh/wifi/ContentHelper.h"
//#include <Arduino.h>
//#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'
}
}

View File

@ -0,0 +1,8 @@
#include <Arduino.h>
#include <functional>
void replaceAll(std::string &str, const std::string &from, const std::string &to);

View File

@ -2,14 +2,7 @@
#include <functional>
/*
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

View File

@ -1,12 +1,12 @@
#include "meshwifi/meshhttp.h"
#include "mesh/wifi/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/wifi/ContentHelper.h"
#include "mesh/wifi/ContentStatic.h"
#include "mesh/wifi/WiFiAPClient.h"
#include "sleep.h"
#include <HTTPBodyParser.hpp>
#include <HTTPMultipartBodyParser.hpp>
@ -15,6 +15,7 @@
#include <WebServer.h>
#include <WiFi.h>
// Persistant Data Storage
#include <Preferences.h>
Preferences prefs;
@ -196,6 +197,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 +255,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 +355,97 @@ void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::function<voi
timeSpeedUp = millis();
}
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");
}
void handleStaticPost(HTTPRequest *req, HTTPResponse *res)
{
// Assume POST request. Contains submitted data.
@ -816,10 +922,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 +982,6 @@ void handleHotspot(HTTPRequest *req, HTTPResponse *res)
res->println("<meta http-equiv=\"refresh\" content=\"0;url=/\" />\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 +1011,8 @@ void handleRoot(HTTPRequest *req, HTTPResponse *res)
res->printf("<p></p>\n");
res->printf("<p>You have gotten this error because the filesystem for the web server has not been loaded.</p>\n");
res->printf("<p>Please review the 'Common Problems' section of the <a "
"href=https://github.com/meshtastic/Meshtastic-device/wiki/How-to-use-the-Meshtastic-Web-Interface-over-WiFi>web interface</a> documentation.</p>\n");
"href=https://github.com/meshtastic/Meshtastic-device/wiki/"
"How-to-use-the-Meshtastic-Web-Interface-over-WiFi>web interface</a> documentation.</p>\n");
return;
}
@ -1210,13 +1226,3 @@ void handleFavicon(HTTPRequest *req, HTTPResponse *res)
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'
}
}

47
src/mesh/wifi/WebServer.h Normal file
View File

@ -0,0 +1,47 @@
#pragma once
#include "PhoneAPI.h"
#include "concurrency/OSThread.h"
#include <Arduino.h>
#include <functional>
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;

View File

@ -1,9 +1,9 @@
#include "meshwifi.h"
#include "mesh/wifi/WiFiAPClient.h"
#include "NodeDB.h"
#include "mesh/wifi/WiFiServerAPI.h"
#include "configuration.h"
#include "main.h"
#include "meshwifi/meshhttp.h"
#include "mesh/wifi/WebServer.h"
#include "target_specific.h"
#include <DNSServer.h>
#include <ESPmDNS.h>

View File

@ -1,38 +0,0 @@
#pragma once
#include "PhoneAPI.h"
#include <Arduino.h>
#include <functional>
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
};

View File

@ -7,7 +7,7 @@
#include "esp_bt.h"
#include "host/util/util.h"
#include "main.h"
#include "meshwifi/meshwifi.h"
#include "mesh/wifi/WiFiAPClient.h"
#include "nimble/NimbleDefs.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"

View File

@ -1,5 +1,5 @@
#include "meshwifi/meshhttp.h"
#include "meshwifi/meshwifi.h"
#include "mesh/wifi/WebServer.h"
#include "mesh/wifi/WiFiAPClient.h"
void initWifi(bool forceSoftAP) {}