From 0518f070a26d19d5d8274593821ec2998c589d5e Mon Sep 17 00:00:00 2001 From: "Hans P. Reiser" Date: Tue, 23 Apr 2019 14:49:29 +0200 Subject: [PATCH] v0.4: merging pull request by DL2MF and some minor modifications --- README.md | 34 ++-- RX_FSK/RX_FSK.ino | 300 ++++++++++++++++++++++++--------- RX_FSK/data/config.txt | 57 +++++++ RX_FSK/data/index.html | 32 +++- RX_FSK/data/networks.txt | 2 - RX_FSK/data/qrg.txt | 23 ++- Setup.md | 3 + libraries/SondeLib/DFM.cpp | 8 +- libraries/SondeLib/RS41.cpp | 18 +- libraries/SondeLib/RS41.h | 2 +- libraries/SondeLib/Scanner.cpp | 25 ++- libraries/SondeLib/Sonde.cpp | 189 +++++++++++++++------ libraries/SondeLib/Sonde.h | 42 +++-- libraries/SondeLib/aprs.cpp | 45 ++++- libraries/SondeLib/aprs.h | 3 +- 15 files changed, 578 insertions(+), 205 deletions(-) create mode 100644 RX_FSK/data/config.txt diff --git a/README.md b/README.md index 562f1bc..2666c61 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,20 @@ RDZ_TTGO_SONDE This a simple, experimental, not (well) tested, and incomplete decoder for radiosonde RS41 and DFM06/09 on a TTGO LoRa ESP32 with OLED display board. +There have been made some additions for TTGO LoRa ESP32 with only RST button. +Please check also your OLED port settings, both versions use different ports. +You can setup the depending ports in config.txt, 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 + ## Button commands You can use the button on the board (not the reset button, the second one) to issue some commands. The software distinguishes between several inputs: -SHORT Short button press (<1.5 seconds) -DOUBLE Short button press, followed by another button press within 0.5 seconds -MID Medium-length button press (2-4 seconds) -LONG Long button press (>5 seconds) +- SHORT Short button press (<1.5 seconds) +- DOUBLE Short button press, followed by another button press within 0.5 seconds +- MID Medium-length button press (2-4 seconds) +- LONG Long button press (>5 seconds) ## Wireless configuration @@ -39,24 +45,16 @@ for the last 18 frames, if reception was successfull (|) or failed (.) A DOUBLE press will switch to scanning mode. A SHORT press will switch to the next channel in channels.txt -# Spectrum mode +## Spectrum mode A medium press will active scan the whole band (400..406 MHz) and display a spectrum diagram (each line == 50 kHz) +For TTGO boards without configurable button there are some new parameter in config.txt: +- spectrum=10 // 0=off / 1-99 number of seconds to show spectrum after restart +- timer=1 // 0=off / 1= show spectrum countdown timer in spectrum display +- marker=1 // 0=off / 1= show channel edge freq in spectrum display ## Setup -Download https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip -and move to your Arduino IDE's libraries directory -Rename to (name without "-master") - -Download https://github.com/me-no-dev/AsyncTCP/archive/master.zip -and move to your Arduino IDE's libraries directory -Rename to (name without "-master") - -Install Arduino ESP32 file system uploader -https://randomnerdtutorials.com/install-esp32-filesystem-uploader-arduino-ide/ -Download https://github.com/me-no-dev/arduino-esp32fs-plugin/releases/download/1.0/ESP32FS-1.0.zip -Move to your Arduino IDE's tools directory - +see Setup.md diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index 2ba2fc0..4fb310d 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -12,13 +13,9 @@ #define LORA_LED 9 -// I2C OLED Display works with SSD1306 driver -#define OLED_SDA 4 -#define OLED_SCL 15 -#define OLED_RST 16 - // UNCOMMENT one of the constructor lines below -U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ OLED_SCL, /* data=*/ OLED_SDA, /* reset=*/ OLED_RST); // Unbuffered, basic graphics, software I2C +U8X8_SSD1306_128X64_NONAME_SW_I2C *u8x8=NULL; // initialize later after reading config file +//U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ OLED_SCL, /* data=*/ OLED_SDA, /* reset=*/ OLED_RST); // Unbuffered, basic graphics, software I2C //U8G2_SSD1306_128X64_NONAME_1_SW_I2C Display(U8G2_R0, /* clock=*/ OLED_SCL, /* data=*/ OLED_SDA, /* reset=*/ OLED_RST); // Page buffer, SW I2C //U8G2_SSD1306_128X64_NONAME_F_SW_I2C Display(U8G2_R0, /* clock=*/ OLED_SCL, /* data=*/ OLED_SDA, /* reset=*/ OLED_RST); // Full framebuffer, SW I2C @@ -28,20 +25,14 @@ AsyncWebServer server(80); #define LOCALUDPPORT 9002 -// moved to sonde.config -//const char * udpAddress = "192.168.42.20"; -//const int udpPort = 9002; - boolean connected = false; WiFiUDP udp; - // Set LED GPIO -const int ledPin = 2; +int ledPin = 1; // Stores LED state String ledState; - // Replaces placeholder with LED state value String processor(const String& var){ Serial.println(var); @@ -90,6 +81,7 @@ void setupChannelList() { } int i=0; sonde.clearSonde(); + Serial.println("Reading channel config:"); while(file.available()) { String line = file.readStringUntil('\n'); if(!file.available()) break; @@ -104,8 +96,9 @@ void setupChannelList() { else if (space[1]=='6') { type=STYPE_DFM06; } else continue; int active = space[3]=='+'?1:0; - Serial.printf("Adding %f with type %d (active: %d)\n",freq,type,active); - sonde.addSonde(freq, type, active); + char *launchsite = strchr(line.c_str(), ' '); + Serial.printf("Add %f - type %d (on/off: %d)- Site: \n",freq,type,active,launchsite); + sonde.addSonde(freq, type, active, launchsite); i++; } } @@ -113,7 +106,7 @@ void setupChannelList() { const char *createQRGForm() { char *ptr = message; strcpy(ptr,"
"); - for(int i=0; i<10; i++) { + for(int i=0; i=sonde.nSonde?2:sonde.sondeList[i].type); sprintf(ptr+strlen(ptr), "" "" @@ -160,6 +153,9 @@ const char *handleQRGPost(AsyncWebServerRequest *request) { f.printf("%3.3f %c %c\n", atof(fstr), typech, active?'+':'-'); } f.close(); + Serial.println("Channel setup finished"); + Serial.println(); + setupChannelList(); } @@ -251,9 +247,9 @@ void addSondeStatus(char *ptr, int i) sprintf(ptr+strlen(ptr),"\n", s->freq, sondeTypeStr[s->type], s->validID?s->id:"", - s->lat, s->lon, s->hei); - sprintf(ptr+strlen(ptr), "", s->lat, s->lon); strcat(ptr, "
IDActiveFreqMode
%d
%3.3f MHz, Type: %s
ID: %s
QTH: %.6f,%.6f h=%.0fm
Geo-Ref -", s->lat, s->lon); - sprintf(ptr+strlen(ptr), "Google map - ", s->lat, s->lon); + s->lat, s->lon, s->alt); + sprintf(ptr+strlen(ptr), "
GEO-App - ", s->lat, s->lon); + sprintf(ptr+strlen(ptr), "WX.DL2MF.de - ", s->id); sprintf(ptr+strlen(ptr), "OSM

\n"); } @@ -271,13 +267,31 @@ const char *createStatusForm() { ///////////////////// Config form + +void setupConfigData() { + File file = SPIFFS.open("/config.txt", "r"); + if(!file) { + Serial.println("There was an error opening the file '/config.txt' for reading"); + return; + } + while(file.available()) { + String line = file.readStringUntil('\n'); + sonde.setConfig(line.c_str()); + } +} + + struct st_configitems { const char *label; int type; // 0: numeric; i>0 string of length i; -1: separator; -2: type selector void *data; }; -#define N_CONFIG 16 +#define N_CONFIG 20 struct st_configitems config_list[N_CONFIG] = { + {"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}, @@ -400,11 +414,11 @@ void SetupAsyncServer() { const char *fetchWifiPw(const char *id) { for(int i=0; ibegin(); + delay(100); + + u8x8->clear(); + + u8x8->setFont(u8x8_font_7x14_1x2_r); + u8x8->drawString(1, 1, "RDZ_TTGO_SONDE"); + u8x8->drawString(2, 3, " V0.1e"); + u8x8->drawString(1, 5, "Mods by DL2MF"); + delay(3000); + + sonde.clearDisplay(); + setupWifiList(); + button1.pin = sonde.config.button_pin; + + // == show initial values from config.txt ========================= // + if (sonde.config.debug == 1) { + u8x8->setFont(u8x8_font_chroma48medium8_r); + u8x8->drawString(0, 0, "Config:"); + + delay(500); + itoa(sonde.config.oled_sda, buf, 10); + u8x8->drawString(0, 1, " SDA:"); + u8x8->drawString(6, 1, buf); + + delay(500); + itoa(sonde.config.oled_scl, buf, 10); + u8x8->drawString(0, 2, " SCL:"); + u8x8->drawString(6, 2, buf); + + delay(500); + itoa(sonde.config.oled_rst, buf, 10); + u8x8->drawString(0, 3, " RST:"); + u8x8->drawString(6, 3, buf); + + delay(1000); + itoa(sonde.config.led_pin, buf, 10); + u8x8->drawString(0, 4, " LED:"); + u8x8->drawString(6, 4, buf); + + delay(500); + itoa(sonde.config.spectrum, buf, 10); + u8x8->drawString(0, 5, " SPEC:"); + u8x8->drawString(6, 5, buf); + + delay(500); + itoa(sonde.config.maxsonde, buf, 10); + u8x8->drawString(0, 6, " MAX:"); + u8x8->drawString(6, 6, buf); + + delay(5000); + sonde.clearDisplay(); + } + // == show initial values from config.txt ========================= // + #if 0 + // == check the radio chip by setting default frequency =========== // if(rs41.setFrequency(402700000)==0) { Serial.println(F("Setting freq: SUCCESS ")); } else { @@ -481,6 +553,7 @@ void setup() float f = sx1278.getFrequency(); Serial.print("Frequency set to "); Serial.println(f); + // == check the radio chip by setting default frequency =========== // #endif //sx1278.setLNAGain(-48); @@ -491,11 +564,10 @@ void setup() Serial.println(gain); // Print a success message - Serial.println(F("sx1278 configured finished")); - Serial.println(); - + Serial.println(F("SX1278 configuration finished")); Serial.println("Setup finished"); + Serial.println(); // int returnValue = pthread_create(&wifithread, NULL, wifiloop, (void *)0); // if (returnValue) { @@ -504,22 +576,28 @@ void setup() // xTaskCreate(mainloop, "MainServer", 10240, NULL, 10, NULL); // Handle button press - attachInterrupt(0, buttonISR, CHANGE); + attachInterrupt(button1.pin, buttonISR, CHANGE); + // == setup default channel list if qrg.txt read fails =========== // setupChannelList(); #if 0 sonde.clearSonde(); - sonde.addSonde(402.300, STYPE_RS41); sonde.addSonde(402.700, STYPE_RS41); + sonde.addSonde(405.700, STYPE_RS41); + sonde.addSonde(405.900, STYPE_RS41); sonde.addSonde(403.450, STYPE_DFM09); + Serial.println("No channel config file, using defaults!"); + Serial.println(); #endif /// not here, done by sonde.setup(): rs41.setup(); + // == setup default channel list if qrg.txt read fails =========== // + sonde.setup(); } enum MainState { ST_DECODER, ST_SCANNER, ST_SPECTRUM, ST_WIFISCAN }; -static MainState mainState = ST_DECODER; +static MainState mainState = ST_WIFISCAN; void enterMode(int mode) { mainState = (MainState)mode; @@ -530,6 +608,8 @@ void loopDecoder() { switch(getKeyPress()) { case KP_SHORT: sonde.nextConfig(); + sonde.updateDisplayRXConfig(); + sonde.updateDisplay(); break; case KP_DOUBLE: enterMode(ST_SCANNER); @@ -551,7 +631,8 @@ void loopDecoder() { Serial.println("Sending position via UDP"); SondeInfo *s = sonde.si(); char raw[201]; - const char *str = aprs_senddata(s->lat, s->lon, s->hei, s->hs, s->dir, s->vs, sondeTypeStr[s->type], s->id, "TE0ST", "EO"); + const char *str = aprs_senddata(s->lat, s->lon, s->alt, s->hs, s->dir, s->vs, sondeTypeStr[s->type], s->id, "TE0ST", + sonde.config.udpfeed.symbol); int rawlen = aprsstr_mon2raw(str, raw, APRS_MAXLEN); Serial.print("Sending: "); Serial.println(raw); udp.beginPacket(sonde.config.udpfeed.host,sonde.config.udpfeed.port); @@ -580,7 +661,7 @@ void loopScanner() { } // receiveFrame returns 0 on success, 1 on timeout int res = sonde.receiveFrame(); // Maybe instead of receiveFrame, just detect if right type is present? TODO - Serial.print("Scanner: receiveFrame returned"); + Serial.print("Scanner: receiveFrame returned: "); Serial.println(res); if(res==0) { enterMode(ST_DECODER); @@ -645,71 +726,121 @@ void WiFiEvent(WiFiEvent_t event){ } } - static char* _scan[2]={"/","\\"}; void loopWifiScan() { - u8x8.setFont(u8x8_font_chroma48medium8_r); - u8x8.drawString(0,0,"WiFi Scan..."); + u8x8->setFont(u8x8_font_chroma48medium8_r); + if (sonde.config.wifi != 0) { + u8x8->drawString(0,0,"WiFi Scan..."); + } + else if (sonde.config.wifiap != 0) { + u8x8->drawString(0,0,"WiFi AP-Mode:"); + } + int line=0; int cnt=0; + int marker=0; + char buf[5]; WiFi.disconnect(true); WiFi.mode(WIFI_STA); const char *id, *pw; - 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()); - line = (line+1)%5; - Serial.print("Signal strength: "); - Serial.println(WiFi.RSSI(i)); - Serial.print("MAC address: "); - Serial.println(WiFi.BSSIDstr(i)); - Serial.print("Encryption type: "); - String encryptionTypeDescription = translateEncryptionType(WiFi.encryptionType(i)); - Serial.println(encryptionTypeDescription); - Serial.println("-----------------------"); - id=WiFi.SSID(i).c_str(); - pw=fetchWifiPw(id); - if(pw) break; - } - if(!pw) { id="test"; pw="test"; } - Serial.print("Connecting to: "); Serial.println(id); - u8x8.drawString(0,6, "Conn:"); - u8x8.drawString(6,6, id); - //register event handler - WiFi.onEvent(WiFiEvent); + char idstr[64]="test"; + + if (sonde.config.wifi != 0) { + 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()); + line = (line+1)%5; + Serial.print("Signal strength: "); + Serial.println(WiFi.RSSI(i)); + Serial.print("MAC address: "); + Serial.println(WiFi.BSSIDstr(i)); + Serial.print("Encryption type: "); + String encryptionTypeDescription = translateEncryptionType(WiFi.encryptionType(i)); + Serial.println(encryptionTypeDescription); + Serial.println("-----------------------"); + id=WiFi.SSID(i).c_str(); + pw=fetchWifiPw(id); + if(pw) { strncpy(idstr, id, 63); } + } + if(!pw) { pw="test"; } + Serial.print("Connecting to: "); Serial.println(idstr); + u8x8->drawString(0,6, "Conn:"); + u8x8->drawString(6,6, idstr); + //register event handler + WiFi.onEvent(WiFiEvent); + + WiFi.begin(idstr, pw); + } - WiFi.begin(id, pw); while(WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); - u8x8.drawString(15,7,_scan[cnt&1]); + u8x8->drawString(15,7,_scan[cnt&1]); cnt++; #if 0 if(cnt==4) { WiFi.disconnect(true); // retry, for my buggy FritzBox WiFi.onEvent(WiFiEvent); - WiFi.begin(id, pw); + WiFi.begin(idstr, pw); } #endif if(cnt==15) { WiFi.disconnect(true); - delay(1000); - WiFi.softAP(networks[0].id.c_str(),networks[0].pw.c_str()); - IPAddress myIP = WiFi.softAPIP(); - Serial.print("AP IP address: "); - Serial.println(myIP); - u8x8.drawString(0,6, "AP: "); - u8x8.drawString(6,6, networks[0].id.c_str()); - sonde.setIP(myIP.toString().c_str(), true); - sonde.updateDisplayIP(); - SetupAsyncServer(); - delay(5000); - enterMode(ST_DECODER); + + if (sonde.config.wifiap != 0) { // enable WiFi AP mode in config.txt: wifi=1 + delay(1000); + WiFi.softAP(networks[0].id.c_str(),networks[0].pw.c_str()); + IPAddress myIP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(myIP); + u8x8->drawString(0,6, "AP: "); + u8x8->drawString(6,6, networks[0].id.c_str()); + sonde.setIP(myIP.toString().c_str(), true); + sonde.updateDisplayIP(); + SetupAsyncServer(); + delay(3000); + } + + if (sonde.config.spectrum != 0) { // enable Spectrum in config.txt: spectrum=number_of_seconds + sonde.clearDisplay(); + u8x8->setFont(u8x8_font_chroma48medium8_r); + u8x8->drawString(0, 0, "Spectrum Scan..."); + delay(500); + + enterMode(ST_SPECTRUM); + + for (int i = 0; i < sonde.config.spectrum; i++) { + scanner.scan(); + scanner.plotResult(); + + if (sonde.config.marker != 0) { + itoa((sonde.config.startfreq), buf, 10); + u8x8->drawString(0, 1, buf); + u8x8->drawString(7, 1, "MHz"); + itoa((sonde.config.startfreq + 6), buf, 10); + u8x8->drawString(13, 1, buf); + } + + if (sonde.config.timer != 0) { + itoa((sonde.config.spectrum - i), buf, 10); + if (sonde.config.marker != 0) { + marker = 1; + } + u8x8->drawString(0, 1+marker, buf); + u8x8->drawString(2, 1+marker, "Sec."); + } + } + + delay(1000); + } + + enterMode(ST_SCANNER); return; } + } Serial.println(""); @@ -719,10 +850,11 @@ void loopWifiScan() { sonde.setIP(WiFi.localIP().toString().c_str(), false); sonde.updateDisplayIP(); SetupAsyncServer(); - delay(5000); - enterMode(ST_DECODER); -} + delay(2000); + // enterMode(ST_DECODER); ### 2019-04-20 - changed DL2MF + enterMode(ST_SCANNER); +} void loop() { Serial.println("Running main loop"); diff --git a/RX_FSK/data/config.txt b/RX_FSK/data/config.txt new file mode 100644 index 0000000..e26aa9e --- /dev/null +++ b/RX_FSK/data/config.txt @@ -0,0 +1,57 @@ +#-------------------------------# +# Hardware depending settings +#-------------------------------# +button_pin=0 +# LED port +led_pin=25 +# 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=4 +oled_scl=15 +oled_rst=16 +#-------------------------------# +# General config settings +#-------------------------------# +maxsonde=20 +debug=0 +wifi=0 +wifiap=1 +#-------------------------------# +# Spectrum display settings +#-------------------------------# +startfreq=400 +channelbw=10 +spectrum=10 +timer=1 +noisefloor=-110 +marker=1 +#-------------------------------# +# APRS settings +#-------------------------------# +call=N0CALL +passcode=12345 +#-------------------------------# +# axudp for sending to aprsmap +#-------------------------------# +# local use only, do not feed to public services +# data not sanitized / quality checked, outliers not filtered out +axudp.active=1 +axudp.host=192.168.42.20 +axudp.port=9002 +axudp.symbol=/O +axudp.highrate=1 +axudp.idformat=0 +#-------------------------------# +# maybe some time in the future +#-------------------------------# +# currently simply not implemented, no need to put anything here anyway +tcp.active=0 +tcp.host=radiosondy.info +tcp.port=14590 +tcp.symbol=/O +tcp.highrate=20 +tcp.idformat=0 +#-------------------------------# +# EOF +#-------------------------------# diff --git a/RX_FSK/data/index.html b/RX_FSK/data/index.html index 35a3775..881b554 100644 --- a/RX_FSK/data/index.html +++ b/RX_FSK/data/index.html @@ -1,13 +1,13 @@ - ESP32 Web Server + RDZSonde Server -

ESP32 Web Server

+

RDZSonde Server