From 26299535c52b15186d30ffe2fb6c905ebaa4a0a8 Mon Sep 17 00:00:00 2001 From: "Hansi, dl9rdz" Date: Mon, 29 Apr 2019 22:00:09 +0200 Subject: [PATCH 1/2] v0.6: - More correct C++ code for WiFi scan (might fix some network problems) - Automated build and deploy process using Travis - Automated selection of v1 or v2 boards (tested only with my boards) - Settings (config.txt) configurable via web interface Squashed commit of the following: commit 0dd00a8eeba1296fb3d6d9dee0720308ec1d2f64 Author: Hansi, dl9rdz Date: Mon Apr 29 21:59:10 2019 +0200 spectrum timer fixes for v1 boards commit 016c060df4570ebec5900019538571b2ee3f2292 Author: Hansi, dl9rdz Date: Mon Apr 29 21:35:42 2019 +0200 fixed potential C++ object lifetime problems with dangling pointers commit 42f575043826f87573895c1961f98764bc08a86b Author: Hansi, dl9rdz Date: Mon Apr 29 18:19:02 2019 +0200 nicer download page commit 01229e0160358a03239b2201399cf26c7fe30f93 Author: Hansi, dl9rdz Date: Mon Apr 29 18:13:24 2019 +0200 configuration editable via web --- .travis/push.sh | 15 ++- RX_FSK/RX_FSK.ino | 166 ++++++++++++++++++++++++--------- RX_FSK/data/config.txt | 7 +- RX_FSK/version.h | 2 +- libraries/SondeLib/Scanner.cpp | 3 +- libraries/SondeLib/Sonde.cpp | 16 +++- 6 files changed, 155 insertions(+), 54 deletions(-) diff --git a/.travis/push.sh b/.travis/push.sh index 360149b..92fcf3f 100755 --- a/.travis/push.sh +++ b/.travis/push.sh @@ -4,19 +4,26 @@ setup_git() { git config --global user.name "dl9rdz (via Travis CI)" } generate_website_index() { - echo "" > download.html - echo "

Master repository

    " >> download.html + echo "" > download.html + echo "" >> download.html + echo "rdz_ttgo_sonde" >> download.html + echo '' >> download.html + echo "" >> download.html + echo '

    rdz_ttgo_sonde

    ' >> download.html + echo '

    View the Project on GitHub dl9rdz/rdz_ttgo_sonde

    ' >> download.html + echo '

    rdz_ttgo_sonde

    ' >> download.html + echo "

    Master repository

      " >> download.html for i in `ls master`; do TS=`git log master/$i | grep "Date:" | head -1 | awk '{$1="";$2="";$7="";print substr($0,3,length($0)-3)}'` if [ -z "$TS" ]; then TS=`date`; fi echo "
    • $i ($TS)
    • \n" >> download.html; done - echo "

    Development repository

      " >> download.html + echo "

    Development repository

      " >> download.html for i in `ls devel`; do TS=`git log devel/$i | grep "Date:" | head -1 | awk '{$1="";$2="";$7="";print substr($0,3,length($0)-3)}'` echo "
    • $i ($TS)
    • \n" >> download.html; done - echo "
    " >> download.html + echo "
" >> download.html git add download.html git commit --message "Travis build: $TRAVIS_BUILD_NUMBER" } diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index bf7b855..ee56e1c 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -33,6 +33,9 @@ int ledPin = 1; // Stores LED state String ledState; +// timestamp when spectrum display was activated +static unsigned long specTimer; + // Replaces placeholder with LED state value String processor(const String& var) { Serial.println(var); @@ -75,7 +78,8 @@ const String sondeTypeSelect(int activeType) { //trying to work around //"assertion "heap != NULL && "free() target pointer is outside heap areas"" failed:" // which happens if request->send is called in createQRGForm!?!?? -char message[10240]; +char message[10240*4]; //needs to be large enough for all forms (not checked in code) +// QRG form is currently about 24kb with 100 entries ///////////////////////// Functions for Reading / Writing QRG list from/to qrg.txt @@ -146,7 +150,8 @@ const char *handleQRGPost(AsyncWebServerRequest *request) { #if 0 int params = request->params(); for (int i = 0; i < params; i++) { - Serial.println(request->getParam(i)->name().c_str()); + String pname = request->getParam(i)->name(); + Serial.println(pname.c_str()); } #endif for (int i = 1; i <= sonde.config.maxsonde; i++) { @@ -158,8 +163,10 @@ const char *handleQRGPost(AsyncWebServerRequest *request) { snprintf(label, 10, "T%d", i); AsyncWebParameter *type = request->getParam(label, true); if (!type) continue; - const char *fstr = freq->value().c_str(); - const char *tstr = type->value().c_str(); + String fstring = freq->value(); + String tstring = type->value(); + const char *fstr = fstring.c_str(); + const char *tstr = tstring.c_str(); Serial.printf("Processing a=%s, f=%s, t=%s\n", active ? "YES" : "NO", fstr, tstr); char typech = (tstr[2] == '4' ? '4' : tstr[3]); // Ugly TODO f.printf("%3.3f %c %c\n", atof(fstr), typech, active ? '+' : '-'); @@ -238,7 +245,8 @@ const char *handleWIFIPost(AsyncWebServerRequest *request) { #if 0 int params = request->params(); for (int i = 0; i < params; i++) { - Serial.println(request->getParam(i)->name().c_str()); + String param = request->getParam(i)->name(); + Serial.println(param.c_str()); } #endif for (int i = 1; i <= MAX_WIFI; i++) { @@ -248,8 +256,10 @@ const char *handleWIFIPost(AsyncWebServerRequest *request) { snprintf(label, 10, "P%d", i); AsyncWebParameter *pw = request->getParam(label, true); if (!pw) continue; - const char *sstr = ssid->value().c_str(); - const char *pstr = pw->value().c_str(); + String sstring = ssid->value(); + String pstring = pw->value(); + const char *sstr = sstring.c_str(); + const char *pstr = pstring.c_str(); if (strlen(sstr) == 0) continue; Serial.printf("Processing S=%s, P=%s\n", sstr, pstr); f.printf("%s\n%s\n", sstr, pstr); @@ -301,32 +311,49 @@ void setupConfigData() { struct st_configitems { + const char *name; const char *label; int type; // 0: numeric; i>0 string of length i; -1: separator; -2: type selector void *data; }; struct st_configitems config_list[] = { - {"ShowSpectrum (s)", 0, &sonde.config.spectrum}, - {"Startfreq (MHz)", 0, &sonde.config.startfreq}, - {"Bandwidth (kHz)", 0, &sonde.config.channelbw}, - {"---", -1, NULL}, - {"Call", 8, sonde.config.call}, - {"Passcode", 8, sonde.config.passcode}, - {"---", -1, NULL}, - {"AXUDP active", -3, &sonde.config.udpfeed.active}, - {"AXUDP Host", 63, sonde.config.udpfeed.host}, - {"AXUDP Port", 0, &sonde.config.udpfeed.port}, - {"DFM ID Format", -2, &sonde.config.udpfeed.idformat}, - {"Rate limit", 0, &sonde.config.udpfeed.highrate}, - {"---", -1, NULL}, - {"APRS TCP active", -3, &sonde.config.tcpfeed.active}, - {"ARPS TCP Host", 63, sonde.config.tcpfeed.host}, - {"APRS TCP Port", 0, &sonde.config.tcpfeed.port}, - {"DFM ID Format", -2, &sonde.config.tcpfeed.idformat}, - {"Rate limit", 0, &sonde.config.tcpfeed.highrate}, - {"---", -1, NULL}, - {"Spectrum noise floor", 0, &sonde.config.noisefloor} + /* General config settings */ + {"wifi","Wifi mode (0/1/2/3)", 0, &sonde.config.wifi}, + {"debug","Debug mode (0/1)", 0, &sonde.config.debug}, + {"maxsonde","Maxsonde (requires reboot?)", 0, &sonde.config.maxsonde}, + /* Spectrum display settings */ + {"spectrum","ShowSpectrum (s)", 0, &sonde.config.spectrum}, + {"startfreq","Startfreq (MHz)", 0, &sonde.config.startfreq}, + {"channelbw","Bandwidth (kHz)", 0, &sonde.config.channelbw}, + {"timer","Spectrum Timer", 0, &sonde.config.timer}, + {"marker","Spectrum MHz marker", 0, &sonde.config.marker}, + {"noisefloor","Sepctrum noisefloor", 0, &sonde.config.noisefloor}, + {"---", "---", -1, NULL}, + /* APRS settings */ + {"call","Call", 8, sonde.config.call}, + {"passcode","Passcode", 8, sonde.config.passcode}, + {"---", "---", -1, NULL}, + /* AXUDP settings */ + {"axudp.active","AXUDP active", -3, &sonde.config.udpfeed.active}, + {"axudp.host","AXUDP Host", 63, sonde.config.udpfeed.host}, + {"axudp.port","AXUDP Port", 0, &sonde.config.udpfeed.port}, + {"axudp.idformat","DFM ID Format", -2, &sonde.config.udpfeed.idformat}, + {"axudp.highrate","Rate limit", 0, &sonde.config.udpfeed.highrate}, + {"---", "---", -1, NULL}, + /* APRS TCP settings, current not used */ + {"tcp.active","APRS TCP active", -3, &sonde.config.tcpfeed.active}, + {"tcp.host","ARPS TCP Host", 63, sonde.config.tcpfeed.host}, + {"tcp.port","APRS TCP Port", 0, &sonde.config.tcpfeed.port}, + {"tcp.idformat","DFM ID Format", -2, &sonde.config.tcpfeed.idformat}, + {"tcp.highrate","Rate limit", 0, &sonde.config.tcpfeed.highrate}, + {"---", "---", -1, NULL}, + /* Hardware dependeing settings */ + {"oled_sda","OLED SDA (needs reboot)", 0, &sonde.config.oled_sda}, + {"oled_scl","OLED SCL (needs reboot)", 0, &sonde.config.oled_scl}, + {"oled_rst","OLED RST (needs reboot)", 0, &sonde.config.oled_rst}, + {"button_pin","Button input port (needs reboot)", 0, &sonde.config.button_pin}, + {"led_pout","LED output port (needs reboot)", 0, &sonde.config.led_pout}, }; const static int N_CONFIG=(sizeof(config_list)/sizeof(struct st_configitems)); @@ -371,11 +398,46 @@ const char *createConfigForm() { break; } } - strcat(ptr, ""); + strcat(ptr, ""); return message; } +const char *handleConfigPost(AsyncWebServerRequest *request) { + char label[10]; + // parameters: a_i, f_1, t_i (active/frequency/type) +#if 1 + File f = SPIFFS.open("/config.txt", "w"); + if (!f) { + Serial.println("Error while opening '/config.txt' for writing"); + return "Error while opening '/config.txt' for writing"; + } +#endif + Serial.println("Handling post request"); +#if 1 + int params = request->params(); + for (int i = 0; i < params; i++) { + String param = request->getParam(i)->name(); + Serial.println(param.c_str()); + } +#endif + for (int i = 0; i < params; i++) { + String strlabel = request->getParam(i)->name(); + const char *label = strlabel.c_str(); + if(strncmp(label, "CFG", 3)!=0) continue; + int idx = atoi(label+3); + Serial.printf("idx is %d\n", idx); + if(config_list[idx].type == -1) continue; // skip separator entries, should not happen + AsyncWebParameter *value = request->getParam(label, true); + if(!value) continue; + String strvalue = value->value(); + Serial.printf("Processing %s=%s\n", config_list[idx].name, strvalue.c_str()); + f.printf("%s=%s\n", config_list[idx].name, strvalue.c_str()); + } + f.close(); + setupConfigData(); +} + const char* PARAM_MESSAGE = "message"; void SetupAsyncServer() { @@ -412,7 +474,10 @@ void SetupAsyncServer() { server.on("/config.html", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(200, "text/html", createConfigForm()); }); - + server.on("/config.html", HTTP_POST, [](AsyncWebServerRequest * request) { + handleConfigPost(request); + request->send(200, "text/html", createConfigForm()); + }); server.on("/status.html", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(200, "text/html", createStatusForm()); }); @@ -522,6 +587,11 @@ void setup() char buf[12]; // Open serial communications and wait for port to open: Serial.begin(115200); + for(int i=0; i<39; i++) { + int v = gpio_get_level((gpio_num_t)i); + Serial.printf("%d:%d ",i,v); + } + Serial.println(""); pinMode(LORA_LED, OUTPUT); aprs_gencrctab(); @@ -654,6 +724,11 @@ static MainState mainState = ST_WIFISCAN; // ST_WIFISCAN; void enterMode(int mode) { mainState = (MainState)mode; + if(mainState == ST_SPECTRUM) { + sonde.clearDisplay(); + u8x8->setFont(u8x8_font_chroma48medium8_r); + specTimer = millis(); + } sonde.clearDisplay(); } @@ -726,7 +801,6 @@ void loopScanner() { } } -static unsigned long specTimer; void loopSpectrum() { int marker = 0; @@ -757,6 +831,7 @@ void loopSpectrum() { if (sonde.config.timer) { int remaining = sonde.config.spectrum - (millis() - specTimer)/1000; itoa(remaining, buf, 10); + Serial.printf("timer:%d config.spectrum:%d specTimer:%ld millis:%ld remaining:%d\n",sonde.config.timer, sonde.config.spectrum, specTimer, millis(), remaining); if (sonde.config.marker != 0) { marker = 1; } @@ -773,7 +848,6 @@ void startSpectrumDisplay() { u8x8->setFont(u8x8_font_chroma48medium8_r); u8x8->drawString(0, 0, "Spectrum Scan..."); delay(500); - specTimer = millis(); enterMode(ST_SPECTRUM); } @@ -969,7 +1043,8 @@ void loopWifiBackground() { if (WiFi.isConnected()) { wifi_state = WIFI_CONNECTED; // update IP in display - sonde.setIP(WiFi.localIP().toString().c_str(), false); + String localIPstr = WiFi.localIP().toString(); + sonde.setIP(localIPstr.c_str(), false); sonde.updateDisplayIP(); enableNetwork(true); } @@ -993,7 +1068,8 @@ void startAP() { wifi_state = WIFI_APMODE; WiFi.softAP(networks[0].id.c_str(), networks[0].pw.c_str()); IPAddress myIP = WiFi.softAPIP(); - sonde.setIP(myIP.toString().c_str(), true); + String myIPstr = myIP.toString(); + sonde.setIP(myIPstr.c_str(), true); sonde.updateDisplayIP(); SetupAsyncServer(); } @@ -1013,6 +1089,7 @@ void initialMode() { // 2: access point mode in background. directly start initial mode (spectrum or scanner) // 3: traditional sync. WifiScan. Tries to connect to a network, in case of failure activates AP. // Mode 3 shows more debug information on serial port and display. +#define MAXWIFIDELAY 20 static const char* _scan[2] = {"/", "\\"}; void loopWifiScan() { if (sonde.config.wifi == 0) { // no Wifi @@ -1045,8 +1122,9 @@ void loopWifiScan() { int n = WiFi.scanNetworks(); for (int i = 0; i < n; i++) { Serial.print("Network name: "); - Serial.println(WiFi.SSID(i)); - u8x8->drawString(0, 1 + line, WiFi.SSID(i).c_str()); + String ssid = WiFi.SSID(i); + Serial.println(ssid); + u8x8->drawString(0, 1 + line, ssid.c_str()); line = (line + 1) % 5; Serial.print("Signal strength: "); Serial.println(WiFi.RSSI(i)); @@ -1056,19 +1134,20 @@ void loopWifiScan() { String encryptionTypeDescription = translateEncryptionType(WiFi.encryptionType(i)); Serial.println(encryptionTypeDescription); Serial.println("-----------------------"); - const char *id = WiFi.SSID(i).c_str(); - int curidx = fetchWifiIndex(id); + int curidx = fetchWifiIndex(ssid.c_str()); if (curidx >= 0 && index == -1) { index = curidx; Serial.printf("Match found at scan entry %d, config network %d\n", i, index); } } if (index >= 0) { // some network was found - Serial.print("Connecting to: "); Serial.println(fetchWifiSSID(index)); + Serial.print("Connecting to: "); Serial.print(fetchWifiSSID(index)); + Serial.print(" with password "); Serial.println(fetchWifiPw(index)); + u8x8->drawString(0, 6, "Conn:"); u8x8->drawString(6, 6, fetchWifiSSID(index)); WiFi.begin(fetchWifiSSID(index), fetchWifiPw(index)); - while (WiFi.status() != WL_CONNECTED && cnt < 20) { + while (WiFi.status() != WL_CONNECTED && cnt < MAXWIFIDELAY) { delay(500); Serial.print("."); if (cnt == 5) { @@ -1076,13 +1155,15 @@ void loopWifiScan() { WiFi.disconnect(true); delay(500); WiFi.begin(fetchWifiSSID(index), fetchWifiPw(index)); + Serial.print("Reconnecting to: "); Serial.print(fetchWifiSSID(index)); + Serial.print(" with password "); Serial.println(fetchWifiPw(index)); delay(500); } u8x8->drawString(15, 7, _scan[cnt & 1]); cnt++; } } - if (index < 0 || cnt >= 15) { // no network found, or connect not successful + if (index < 0 || cnt >= MAXWIFIDELAY) { // no network found, or connect not successful WiFi.disconnect(true); delay(1000); startAP(); @@ -1096,8 +1177,9 @@ void loopWifiScan() { Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - sonde.setIP(WiFi.localIP().toString().c_str(), false); + String localIPstr = WiFi.localIP().toString(); + Serial.println(localIPstr); + sonde.setIP(localIPstr.c_str(), false); sonde.updateDisplayIP(); wifi_state = WIFI_CONNECTED; delay(3000); diff --git a/RX_FSK/data/config.txt b/RX_FSK/data/config.txt index e3e098e..a56168a 100644 --- a/RX_FSK/data/config.txt +++ b/RX_FSK/data/config.txt @@ -7,8 +7,9 @@ led_pout=9 # OLED Setup is depending on hardware of LoRa board # TTGO v1: SDA=4 SCL=15, RST=16 # TTGO v2: SDA=21 SCL=22, RST=16 -oled_sda=21 -oled_scl=22 +# No specification in config file: try autodetection (gpio4 pin level at startup) +#oled_sda=21 +#oled_scl=22 oled_rst=16 #-------------------------------# # General config settings @@ -24,7 +25,7 @@ startfreq=400 channelbw=10 spectrum=10 timer=1 -noisefloor=-110 +noisefloor=-125 marker=1 #-------------------------------# # APRS settings diff --git a/RX_FSK/version.h b/RX_FSK/version.h index e5187c3..098c52b 100644 --- a/RX_FSK/version.h +++ b/RX_FSK/version.h @@ -1,2 +1,2 @@ const char *version_name = "RDZ_TTGO_SONDE"; -const char *version_id = "master v0.5e"; +const char *version_id = "devel20190429"; diff --git a/libraries/SondeLib/Scanner.cpp b/libraries/SondeLib/Scanner.cpp index b3ae429..4239910 100644 --- a/libraries/SondeLib/Scanner.cpp +++ b/libraries/SondeLib/Scanner.cpp @@ -23,7 +23,8 @@ int scandisp[NCHAN/PIXSAMPL]; #define PLOT_N 128 #define TICK1 (128/6) #define TICK2 (TICK1/4) -#define PLOT_MIN -250 +//#define PLOT_MIN -250 +#define PLOT_MIN (sonde.config.noisefloor*2) #define PLOT_SCALE(x) (xMAXSONDE) config.maxsonde=MAXSONDE; } else if(strcmp(cfg,"debug")==0) { config.debug = atoi(val); } else if(strcmp(cfg,"wifi")==0) { From 8febd2955abb2b2707a60bae89874398d8361e9b Mon Sep 17 00:00:00 2001 From: "Hansi, dl9rdz" Date: Mon, 29 Apr 2019 22:02:45 +0200 Subject: [PATCH 2/2] v0.6 -- forgot to update version info --- RX_FSK/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RX_FSK/version.h b/RX_FSK/version.h index 098c52b..5a0d015 100644 --- a/RX_FSK/version.h +++ b/RX_FSK/version.h @@ -1,2 +1,2 @@ const char *version_name = "RDZ_TTGO_SONDE"; -const char *version_id = "devel20190429"; +const char *version_id = "master v0.6";