diff --git a/.travis/push.sh b/.travis/push.sh index ff2e613..93e3719 100755 --- a/.travis/push.sh +++ b/.travis/push.sh @@ -63,6 +63,8 @@ commit_website_files() { git add ${BRANCH}/${VERSION}-changelog.txt echo "

${VERSION}

" > ${BRANCH}/update-info.html git add ${BRANCH}/update-info.html + ${MYPATH}/scripts/makefsupdate.py ${MYPATH}/RX_FSK/data/ > ${BRANCH}/update.fs.bin + git add ${BRANCH}/update.fs.bin git commit --message "Travis build: $TRAVIS_BUILD_NUMBER" } upload_files() { diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index ffeedfa..c4f526f 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -21,6 +21,8 @@ #include "src/geteph.h" #include "src/rs92gps.h" #include "src/aprs.h" +#include "src/ShFreqImport.h" + #if FEATURE_MQTT #include "src/mqtt.h" #endif @@ -58,6 +60,7 @@ WiFiClient client; #define SONDEHUB_STATION_UPDATE_TIME (60*60*1000) // 60 min #define SONDEHUB_MOBILE_STATION_UPDATE_TIME (30*1000) // 30 sec WiFiClient shclient; // Sondehub v2 +char shImportInterval = 0, shImport = 0; unsigned long time_last_update = 0; /* SH_LOC_OFF: never send position information to SondeHub SH_LOC_FIXED: send fixed position (if specified in config) to sondehub @@ -146,6 +149,11 @@ String processor(const String& var) { if (var == "VERSION_ID") { return String(version_id); } + if (var == "FULLNAMEID") { + char tmp[128]; + snprintf(tmp, 128, "%s-%c%d", version_id, SPIFFS_MAJOR+'A'-1, SPIFFS_MINOR); + return String(tmp); + } if (var == "AUTODETECT_INFO") { char tmpstr[128]; const char *fpstr; @@ -258,9 +266,18 @@ void HTMLSAVEBUTTON(char *ptr) { const char *createQRGForm() { char *ptr = message; strcpy(ptr, HTMLHEAD); - strcat(ptr, ""); + strcat(ptr, ""); HTMLBODY(ptr, "qrg.html"); //strcat(ptr, "
"); + strcat(ptr, "\n"); + strcat(ptr, "
"); + strcat(ptr, "\n"); +#if 0 strcat(ptr, "
IDActiveFreqLaunchsiteMode
"); for (int i = 0; i < sonde.config.maxsonde; i++) { //String s = sondeTypeSelect(i >= sonde.nSonde ? 2 : sonde.sondeList[i].type); @@ -278,6 +295,7 @@ const char *createQRGForm() { //i + 1, s.c_str()); } strcat(ptr, "
IDActiveFreqLaunchsiteMode
"); +#endif //
"); HTMLSAVEBUTTON(ptr); HTMLBODYEND(ptr); @@ -490,8 +508,8 @@ const char *createStatusForm() { strcpy(ptr, HTMLHEAD); strcat(ptr, ""); - for (int i = 0; i < sonde.nSonde; i++) { - int snum = (i + sonde.currentSonde) % sonde.nSonde; + for (int i = 0; i < sonde.config.maxsonde; i++) { + int snum = (i + sonde.currentSonde) % sonde.config.maxsonde; if (sonde.sondeList[snum].active) { addSondeStatus(ptr, snum); } @@ -547,6 +565,8 @@ void setupConfigData() { String line = readLine(file); //file.readStringUntil('\n'); sonde.setConfig(line.c_str()); } + int shII = atoi(sonde.config.sondehub.fimport); + if(shImportInterval > shII) shImportInterval = shII; } @@ -649,6 +669,7 @@ struct st_configitems config_list[] = { {"sondehub.alt", "Altitude (optional, visible on SondeHub tracker)", 19, &sonde.config.sondehub.alt}, {"sondehub.antenna", "Antenna (optional, visisble on SondeHub tracker)", 63, &sonde.config.sondehub.antenna}, {"sondehub.email", "SondeHub email (optional, only used to contact in case of upload errors)", 63, &sonde.config.sondehub.email}, + {"sondehub.fimport", "SondeHub freq import (interval/maxdist/maxage [min/km/min])", 18, &sonde.config.sondehub.fimport}, #endif }; const int N_CONFIG = (sizeof(config_list) / sizeof(struct st_configitems)); @@ -1097,8 +1118,8 @@ const char *createKMLDynamic() { strcpy(ptr, ""); - for (int i = 0; i < sonde.nSonde; i++) { - int snum = (i + sonde.currentSonde) % sonde.nSonde; + for (int i = 0; i < sonde.config.maxsonde; i++) { + int snum = (i + sonde.currentSonde) % sonde.config.maxsonde; if (sonde.sondeList[snum].active) { addSondeStatusKML(ptr, snum); } @@ -1289,6 +1310,10 @@ void SetupAsyncServer() { request->send(200, "application/vnd.google-earth.kml+xml", createKMLDynamic()); }); + server.on("/upd.html", HTTP_GET, [](AsyncWebServerRequest * request) { + request->send(SPIFFS, "/upd.html", String(), false, processor); + }); + server.onNotFound([](AsyncWebServerRequest * request) { if (request->method() == HTTP_OPTIONS) { request->send(200); @@ -1297,6 +1322,7 @@ void SetupAsyncServer() { if (url.endsWith(".gpx")) request->send(200, "application/gpx+xml", sendGPX(request)); else { + // TODO: set correct type for .js request->send(SPIFFS, url, "text/html"); Serial.printf("URL is %s\n", url.c_str()); //request->send(404); @@ -2266,6 +2292,11 @@ void loopDecoder() { } Serial.println(""); } + +#if FEATURE_SONDEHUB + sondehub_handle_fimport(&shclient); +#endif + // wifi (axudp) or bluetooth (bttnc) active => send packet SondeInfo *s = &sonde.sondeList[rxtask.receiveSonde]; if ((res & 0xff) == 0 && (connected || tncclient.connected() )) { @@ -2844,7 +2875,7 @@ void loopWifiScan() { } if (hasRS92) { geteph(); - if(ephstate==EPH_PENDING) ephstate=EPH_ERROR; + if (ephstate == EPH_PENDING) ephstate = EPH_ERROR; get_eph("/brdc"); } delay(3000); @@ -2867,13 +2898,13 @@ void execOTA() { bool isValidContentType = false; sonde.clearDisplay(); uint8_t dispxs, dispys; - if( ISOLED(sonde.config) ) { - disp.rdis->setFont(FONT_SMALL); - dispxs = dispys = 1; + if ( ISOLED(sonde.config) ) { + disp.rdis->setFont(FONT_SMALL); + dispxs = dispys = 1; } else { - disp.rdis->setFont(5); - dispxs = 18; - dispys = 20; + disp.rdis->setFont(5); + dispxs = 18; + dispys = 20; } String dispHost = updateHost.substring(0, 16); @@ -3137,16 +3168,16 @@ void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) { // Only send email if provided if (strlen(conf->email) != 0) { sprintf(w, - "\"uploader_contact_email\": \"%s\",", - conf->email); + "\"uploader_contact_email\": \"%s\",", + conf->email); w += strlen(w); } // Only send antenna if provided if (strlen(conf->antenna) != 0) { sprintf(w, - "\"uploader_antenna\": \"%s\",", - conf->antenna); + "\"uploader_antenna\": \"%s\",", + conf->antenna); w += strlen(w); } @@ -3219,6 +3250,55 @@ const char *dfmSubtypeStrSH[16] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +void sondehub_handle_fimport(WiFiClient *client) { + if (sonde.config.sondehub.fimport[0] != '0') { + if (shImport == 0) { + sondehub_send_fimport(&shclient); + } else if (shImport == 1) { + int res = ShFreqImport::shImportHandleReply(&shclient); + if (res == 1) { + shImport = 2; // finished + } + } else if (shImport == 2) { + // waiting for next activation... + shImportInterval --; + if (shImportInterval <= 0) { + shImport = 0; + } + } + } +} + +void sondehub_send_fimport(WiFiClient * client) { + if (shState == SH_CONN_APPENDING || shState == SH_CONN_WAITACK) { + // Currently busy with SondeHub data upload + // So do nothing here. + // sond_fimport will be re-sent later, when shState becomes SH_CONN_IDLE + return; + } + // It's time to run, so check prerequisites + float lat = sonde.config.sondehub.lat, lon = sonde.config.sondehub.lon; + if (gpsPos.valid) { + lat = gpsPos.lat; + lon = gpsPos.lon; + } + + char *ptr = strchr(sonde.config.sondehub.fimport, '/'); + shImportInterval = atoi(sonde.config.sondehub.fimport) * 60; + int maxdist = 200; + int maxage = 60; + if (ptr) { + maxdist = atoi(ptr + 1); + ptr = strchr(ptr + 1, '/'); + if (ptr) maxage = atoi(ptr + 1); + } + if ( !isnan(lat) && !isnan(lon) && maxdist > 0 && maxage > 0 && shImportInterval > 0 ) { + int res = ShFreqImport::shImportSendRequest(&shclient, lat, lon, maxdist, maxage); + if (res == 0) shImport = 1; // Request OK: wait for response + else shImport = 2; // Request failed: wait interval, then retry + } +} + // in hours.... max allowed diff UTC <-> sonde time #define SONDEHUB_TIME_THRESHOLD (3) void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub * conf) { @@ -3248,7 +3328,9 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub * if (SH_LOC_AUTO_IS_CHASE) chase = SH_LOC_CHASE; else chase = SH_LOC_FIXED; } - while (client->available() > 0) { + // TODO: This should better be called not in sondehub_send_data, but somewhere where it is called even if no new data is decoded + // shImport==1: software is waiting for a reply to freq info requst, so reading data is handled elsewhere + while (shImport != 1 && client->available() > 0) { // data is available from remote server, process it... int cnt = client->readBytesUntil('\n', rs_msg, MSG_SIZE - 1); rs_msg[cnt] = 0; @@ -3256,6 +3338,7 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub * // If something that looks like a valid HTTP response is received, we are ready to send the next data item if (shState == SH_CONN_WAITACK && cnt > 11 && strncmp(rs_msg, "HTTP/1", 6) == 0) { shState = SH_CONN_IDLE; + sondehub_send_fimport(client); } } @@ -3365,8 +3448,8 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub * // Only send antenna if provided if (strlen(conf->antenna) != 0) { sprintf(w, - "\"uploader_antenna\": \"%s\",", - conf->antenna); + "\"uploader_antenna\": \"%s\",", + conf->antenna); w += strlen(w); } @@ -3400,7 +3483,7 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub * sprintf(w, "}"); if (shState != SH_CONN_APPENDING) { - sondehub_send_header(client, s, conf); + sondehub_send_header(client, s, conf, &timeinfo); sondehub_send_next(client, s, conf, rs_msg, strlen(rs_msg), 1); shState = SH_CONN_APPENDING; shStart = now; @@ -3431,19 +3514,36 @@ void sondehub_finish_data(WiFiClient * client, SondeInfo * s, struct st_sondehub } } -void sondehub_send_header(WiFiClient * client, SondeInfo * s, struct st_sondehub * conf) { +static const char *DAYS[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; +static const char *MONTHS[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Noc", "Dec"}; + +void sondehub_send_header(WiFiClient * client, SondeInfo * s, struct st_sondehub * conf, struct tm *now) { Serial.print("PUT /sondes/telemetry HTTP/1.1\r\n" "Host: "); Serial.println(conf->host); - Serial.println("accept: text/plain\r\n" + Serial.print("accept: text/plain\r\n" "Content-Type: application/json\r\n" "Transfer-Encoding: chunked\r\n"); + client->print("PUT /sondes/telemetry HTTP/1.1\r\n" "Host: "); client->println(conf->host); - client->println("accept: text/plain\r\n" - "Content-Type: application/json\r\n" - "Transfer-Encoding: chunked\r\n"); + client->print("accept: text/plain\r\n" + "Content-Type: application/json\r\n" + "Transfer-Encoding: chunked\r\n"); + if (now) { + Serial.printf("Date: %s, %02d %s %04d %02d:%02d:%02d GMT\r\n", + DAYS[now->tm_wday], now->tm_mday, MONTHS[now->tm_mon], now->tm_year + 1900, + now->tm_hour, now->tm_min, now->tm_sec); + client->printf("Date: %s, %02d %s %04d %02d:%02d:%02d GMT\r\n", + DAYS[now->tm_wday], now->tm_mday, MONTHS[now->tm_mon], now->tm_year + 1900, + now->tm_hour, now->tm_min, now->tm_sec); + } + client->print("User-agent: "); + client->print(version_name); + client->print("/"); + client->println(version_id); + client->println(""); // another cr lf as indication of end of header } void sondehub_send_next(WiFiClient * client, SondeInfo * s, struct st_sondehub * conf, char *chunk, int chunklen, int first) { // send next chunk of JSON request diff --git a/RX_FSK/data/config.txt b/RX_FSK/data/config.txt index 76c8021..0a76b19 100644 --- a/RX_FSK/data/config.txt +++ b/RX_FSK/data/config.txt @@ -129,6 +129,7 @@ sondehub.lon= sondehub.alt= sondehub.antenna= sondehub.email= +sondehub.fimport=0/100/60 #-------------------------------# # EOF #-------------------------------# diff --git a/RX_FSK/data/rdz.js b/RX_FSK/data/rdz.js index 5667d4c..83bba29 100644 --- a/RX_FSK/data/rdz.js +++ b/RX_FSK/data/rdz.js @@ -6,7 +6,7 @@ stypes.set('M', 'M10'); stypes.set('2', 'M20'); stypes.set('3', 'MP3H'); -/* Used by qrg.html in RX_FSK.ino */ +/* (no longer) Used by qrg.html in RX_FSK.ino */ function prep() { var stlist=document.querySelectorAll("input.stype"); for(txt of stlist){ @@ -24,4 +24,19 @@ function prep() { } } -window.onload = prep; +function qrgTable() { + var tab=document.getElementById("divTable"); + + var table = ""; + for(i=0; i"; + table += ""; + table += ""; + table += ""; + } + table += "
IDActiveFreqLaunchsiteMode
"; + tab.innerHTML = table; + prep(); +} diff --git a/RX_FSK/data/upd.html b/RX_FSK/data/upd.html index 8f4bf65..aa5e408 100644 --- a/RX_FSK/data/upd.html +++ b/RX_FSK/data/upd.html @@ -4,7 +4,7 @@ -

Currently installed: devel20210908-B14

+

Currently installed: %FULLNAMEID%

Available master: (...checking...) diff --git a/RX_FSK/src/ShFreqImport.cpp b/RX_FSK/src/ShFreqImport.cpp new file mode 100644 index 0000000..68db393 --- /dev/null +++ b/RX_FSK/src/ShFreqImport.cpp @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include + +#include "ShFreqImport.h" +#include "Sonde.h" + +static int ppos; +static int quotes; +static char id[20]; +static int idpos; +static float lat, lon, freq; +static char type[20]; + +static uint8_t inuse[1+99/8]; // MAXSONDE is 99 + +static char keyword[40]; +static int keywordpos; +static char value[40]; +static int valuepos; + +static int importState; +static float homelat, homelon; + + +// Map SondeHub type string to Stype. -1 for not supported types. +int ShFreqImport::stringToStype(const char *type) { + if(type[2]=='4') return STYPE_RS41; + if(type[2]=='9') return STYPE_RS92; + if(type[1]=='1') return STYPE_M10; + if(type[1]=='2') return STYPE_M20; + if(type[0]=='D') return STYPE_DFM; + if(type[2]=='3') return STYPE_MP3H; // TODO: check if '3' is correct + return -1; // iMet is not supported +} + +// in Display.cpp +extern float calcLatLonDist(float lat1, float lon1, float lat2, float lon2); + +void ShFreqImport::setLabel(int idx, char *id, float lat, float lon) { + snprintf(sonde.sondeList[idx].launchsite, 18, "@%s/%d", id, (int)(calcLatLonDist(homelat, homelon, lat, lon)/1000)); + sonde.sondeList[idx].launchsite[17] = 0; +} + +void ShFreqImport::usekeyvalue() { + printf("\nUSEKEYVALUE: key %s => value %s\n", keyword, value); + if(strcmp(keyword,"lat")==0) lat = atof(value); + if(strcmp(keyword,"lon")==0) lon = atof(value); + if(strcmp(keyword,"frequency")==0) freq = atof(value); + if(strcmp(keyword,"type")==0) strcpy(type, value); +} + +/* populate qrg.txt with frequency of near sonde */ +void ShFreqImport::populate(char *id, float lat, float lon, float freq, const char *type) +{ + printf(" ID %s: %.5f, %.5f f=%.3f, type=%s \n", id, lat, lon, freq, type); + // Skip if freq already exists + int stype = stringToStype(type); + if(stype<0) return; // unsupported type + + // check if frequency exists already + // don't do anything if its a static entry + // update label if its a dynamic SH entry + int i; + for(i=0; i= sonde.config.maxsonde) { + Serial.println("populate: out of free slots"); + return; + } // no more free slots + + sonde.sondeList[ppos].active = 1; + sonde.sondeList[ppos].freq = freq; + sonde.sondeList[ppos].type = (SondeType)stype; + setLabel(ppos, id, lat, lon); + inuse[ppos/8] |= (1<<(ppos&7)); + ppos++; +} + +// clears all remaining automatically filled slots (no longer in SH data) +void ShFreqImport::cleanup() { + Serial.println("Cleanup called ********"); + for(int i=0; i>(i&7))&1) == 0) && *sonde.sondeList[i].launchsite=='@' ) { + Serial.printf("removing #%d\n", i); + sonde.sondeList[i].launchsite[0] = 0; + sonde.sondeList[i].active = 0; + sonde.sondeList[i].freq = 400; + } + } +} + +#define BUFLEN 128 +#define VALLEN 20 +int ShFreqImport::handleChar(char c) { + switch(importState) { + case START: + // wait for initial '{' + if(c=='{') { + lat = NAN; lon = NAN; freq = NAN; *type = 0; + importState++; + } + break; + case BEFOREID: + // what for first '"' in { "A1234567" : { ... } }; or detect end + if(c=='"') { idpos = 0; importState++; } + if(c=='}') { importState = ENDREACHED; } + break; + case COPYID: + // copy ID "A1234567" until second '"' is earched + if(c=='"') { id[idpos] = 0; printf("ID: %s\n", id); importState++; } + else id[idpos++] = c; + break; + case AFTERID: + // wait for '{' in '"A1234567": { ...' + if(c=='{') importState++; + break; + case BEFOREKEY: + if(c=='"') { keywordpos = 0; importState++; } + break; + case COPYKEY: + if(c=='"') { importState++; keyword[keywordpos] = 0; /* printf("Key: >%s<\n", keyword);*/ } + else keyword[keywordpos++] = c; + break; + case AFTERKEY: + if(c==':') { + valuepos = 0; + quotes = 0; + if(strcmp(keyword,"lat")==0 || strcmp(keyword, "lon")==0 || strcmp(keyword, "frequency")==0 ) + importState = BEFORENUMVAL; + else { + if (strcmp(keyword, "type")==0) + importState = BEFORESTRINGVAL; + else + importState = SKIPVAL; + } + } + break; + case BEFORENUMVAL: + if( (c>='0'&&c<='9') || c=='-') { value[0] = c; valuepos=1; importState++; } + break; + case COPYNUMVAL: + if( !(c>='0'&&c<='9') && c!='-' && c!='.' ) { + value[valuepos]=0; importState=SKIPVAL; usekeyvalue(); + if(c!=',' && c!='}') break; + } + else { value[valuepos++] = c; break; } + // intenionall fall-through + case SKIPVAL: + // This is rather fragile, we *should* handle more escaping and so on but do not do so so far, only simple quotes + if(c=='"') quotes = !quotes; + if(quotes) break; + if(c==',') importState = BEFOREKEY; + if(c=='}') { + // we have an ID and all key/value pairs, check if its good.... + if( !isnan(lat) && !isnan(lon) && !isnan(freq) && type[0] ) { + printf("populate %s %f %f %f %s\n", id, lat, lon, freq, type); + populate(id, lat, lon, freq, type); + } else { + printf("Skipping incomplete %s\n", id); + } + importState = ENDORNEXT; + } + break; + case BEFORESTRINGVAL: + if(c=='"') importState++; + break; + case COPYSTRINGVAL: + if(c=='"') { importState=SKIPVAL; value[valuepos]=0; usekeyvalue(); } + else value[valuepos++] = c; + break; + case ENDORNEXT: + // next we have to see either a final "}', or a comma before the next id + if(c==',') importState = BEFOREID; + else if (c=='}') { importState = ENDREACHED; cleanup(); return 1; } + break; + case ENDREACHED: + return 1; + } + return 0; +} + +// lat lon in deg, dist in km, time in minutes +int ShFreqImport::shImportSendRequest(WiFiClient *client, float lat, float lon, int dist, int time) { + if(!client->connected()) { + if(!client->connect(sonde.config.sondehub.host, 80)) { + Serial.println("Connection FAILED"); + return 1; + } + } + Serial.println("Sending SondeHub import request"); + char req[300]; + snprintf(req, 200, "GET /sondes?lat=%f&lon=%f&distance=%d&last=%d HTTP/1.1\r\n" + "Host: %s\r\n" + "Accept: application/json\r\n" + "Cache-Control: no-cache\r\n\r\n", + lat, lon, dist*1000, time*60, sonde.config.sondehub.host); + client->print(req); + Serial.print(req); + importState = START; + homelat = lat; + homelon = lon; + memset(inuse, 0, sizeof(inuse)); + ppos = 0; + return 0; +} + +// return 0 if more data should be read (later), 1 if finished (close connection...) +int ShFreqImport::shImportHandleReply(WiFiClient *client) { + while(client->available()) { + int res = handleChar(client->read()); + if(res) return res; + } + return 0; +} diff --git a/RX_FSK/src/ShFreqImport.h b/RX_FSK/src/ShFreqImport.h new file mode 100644 index 0000000..7e6927a --- /dev/null +++ b/RX_FSK/src/ShFreqImport.h @@ -0,0 +1,30 @@ +#ifndef SH_FREQ_IMPORT_ +#define SH_FREQ_IMPORT_H +// Automated frequency import from SondeHub + +#include + +enum ImportState { START, BEFOREID, COPYID, AFTERID, BEFOREKEY, COPYKEY, AFTERKEY, SKIPVAL, BEFORENUMVAL, COPYNUMVAL, BEFORESTRINGVAL, COPYSTRINGVAL, AFTERPAYLOAD, ENDORNEXT, ENDREACHED }; + +class ShFreqImport { +public: + // Fetch data from sondehub and populate qrg.txt with result + // return: 0: ok; 1: failure + static int shImportSendRequest(WiFiClient *client, float lat, float lon, int dist, int time); + + // return 0: ok, need more data; 1: finished/failure, close connection + // Asynchronous I/O. Handle data if available + static int shImportHandleReply(WiFiClient *client); + +private: + static int stringToStype(const char *type); + static void setLabel(int idx, char *id, float lat, float lon); + static void usekeyvalue(); + static int handleChar(char c); + + // add one entry on available slot at or after ppos + static void populate(char *id, float lat, float lon, float freq, const char *type); + static void cleanup(); +}; + +#endif diff --git a/RX_FSK/src/Sonde.cpp b/RX_FSK/src/Sonde.cpp index 9070745..a527e7a 100644 --- a/RX_FSK/src/Sonde.cpp +++ b/RX_FSK/src/Sonde.cpp @@ -357,26 +357,26 @@ void Sonde::addSonde(float frequency, SondeType type, int active, char *launchsi // called by updateState (only) void Sonde::nextConfig() { currentSonde++; - if(currentSonde>=nSonde) { + if(currentSonde>=config.maxsonde) { currentSonde=0; } // Skip non-active entries (but don't loop forever if there are no active ones) for(int i=0; i=nSonde) currentSonde=0; + if(currentSonde>=config.maxsonde) currentSonde=0; } } } void Sonde::nextRxSonde() { rxtask.currentSonde++; - if(rxtask.currentSonde>=nSonde) { + if(rxtask.currentSonde>=config.maxsonde) { rxtask.currentSonde=0; } for(int i=0; i=nSonde) rxtask.currentSonde=0; + if(rxtask.currentSonde>=config.maxsonde) rxtask.currentSonde=0; } } Serial.printf("nextRxSonde: %d\n", rxtask.currentSonde); @@ -402,7 +402,7 @@ void Sonde::setup() { for(int i=0; i=nSonde) rxtask.currentSonde=0; + if(rxtask.currentSonde>=config.maxsonde) rxtask.currentSonde=0; } } sonde.currentSonde = rxtask.currentSonde; diff --git a/RX_FSK/src/Sonde.h b/RX_FSK/src/Sonde.h index 768cb28..e42b70e 100644 --- a/RX_FSK/src/Sonde.h +++ b/RX_FSK/src/Sonde.h @@ -2,6 +2,8 @@ #ifndef Sonde_h #define Sonde_h +#include + enum DbgLevel { DEBUG_OFF=0, DEBUG_INFO=1, DEBUG_SPARSER=16, DEBUG_DISPLAY=8 }; // to be extended for configuring serial debug output extern uint8_t debug; @@ -194,6 +196,7 @@ struct st_sondehub { char alt[20]; char antenna[64]; char email[64]; + char fimport[20]; }; // to be extended diff --git a/RX_FSK/version.h b/RX_FSK/version.h index 3a6391c..6067d3c 100644 --- a/RX_FSK/version.h +++ b/RX_FSK/version.h @@ -1,4 +1,4 @@ const char *version_name = "rdzTTGOsonde"; -const char *version_id = "devel20210914"; +const char *version_id = "devel20210915"; const int SPIFFS_MAJOR=2; -const int SPIFFS_MINOR=14; +const int SPIFFS_MINOR=16; diff --git a/platformio.ini b/platformio.ini index da20385..fc3488f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,17 +20,13 @@ lib_deps_external = olikraus/U8g2 @ ^2.28.8 AXP202X_Library stevemarple/MicroNMEA @ ^2.0.5 -; nkawu/TFT 22 ILI9225 @ ^1.4.4 me-no-dev/ESP Async WebServer @ ^1.2.3 https://github.com/moononournation/Arduino_GFX#v1.1.5 -; most recent has compile error (initialization order wrong) -; https://github.com/moononournation/Arduino_GFX https://github.com/dx168b/async-mqtt-client [env:ttgo-lora32] platform = https://github.com/platformio/platform-espressif32.git board = ttgo-lora32-v1 -; board_build.partitions = partition.csv framework = arduino monitor_speed = 115200 lib_deps = @@ -38,3 +34,6 @@ lib_deps = ${extra.lib_deps_external} paulstoffregen/Time@^1.6.0 lib_ignore = Time +; board_build.partitions = partition.csv +;build_flags = -Wl,-Map,output.map +;check_tool = clangtidy diff --git a/scripts/makefsupdate.py b/scripts/makefsupdate.py new file mode 100755 index 0000000..3e0a781 --- /dev/null +++ b/scripts/makefsupdate.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +from os import listdir +import sys + +path = sys.argv[1] + +# create update.fs.bin with content: +# filename size CR LF +# data for filename ... + +files = listdir(path) +files = list(filter(lambda x: x.endswith('.js') or x.endswith('.html') or x.endswith('.css'), files)) +for f in files: + with open(path+"/"+f,"rb") as myf: + data=myf.read(-1) + head = str.encode(f + " " + str(len(data)) + "\r\n") + sys.stdout.buffer.write(head) + sys.stdout.buffer.write(data) +