diff --git a/.travis.yml b/.travis.yml index a4f08be..a6f9e6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: c env: global: - - ESP32TOOLS=/home/travis/.arduino15/packages/esp32/hardware/esp32/1.0.4/tools + - ESP32TOOLS=/home/travis/.arduino15/packages/esp32/hardware/esp32/1.0.5/tools - MKSPIFFS=/home/travis/.arduino15/packages/esp32/tools/mkspiffs/0.2.3/mkspiffs before_install: - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16" diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index b6a4394..1738764 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -27,9 +27,9 @@ int e; enum MainState { ST_DECODER, ST_SPECTRUM, ST_WIFISCAN, ST_UPDATE, ST_TOUCHCALIB }; static MainState mainState = ST_WIFISCAN; // ST_WIFISCAN; +const char *mainStateStr[5] = {"DECODER", "SPECTRUM", "WIFISCAN", "UPDATE", "TOUCHCALIB" }; AsyncWebServer server(80); -AsyncWebSocket ws("/ws"); AXP20X_Class axp; #define PMU_IRQ 35 @@ -108,6 +108,7 @@ int readLine(Stream &stream, char *buffer, int maxlen) { return n; } + // Replaces placeholder with LED state value String processor(const String& var) { Serial.println(var); @@ -214,40 +215,57 @@ void setupChannelList() { file.close(); } +const char *HTMLHEAD = "
"; +void HTMLBODY(char *ptr, const char *which) { + strcat(ptr, ""); +} +void HTMLSAVEBUTTON(char *ptr) { + strcat(ptr, "| Option | Value |
|---|
| Option | Value |
|---|
Edit: ", maxlen); + i = strlen(buffer); + strncpy(buffer + i, filename.c_str(), maxlen - i); + i += strlen(buffer + i); + strncpy(buffer + i, "
Something went wrong. Uploaded file is empty.
"); - else - request->send(200, "text/html", createEditForm(request->getParam(0)->value())); + else { + String f = request->getParam(0)->value(); + request->redirect("/edit.html?file=" + f); + //request->send(200, "text/html", createEditForm(request->getParam(0)->value())); + } }, NULL, [](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) { @@ -982,7 +1128,7 @@ void SetupAsyncServer() { // Route to load style.css file server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) { AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/style.css", "text/css"); - response->addHeader("Cache-Control","max-age=86400"); + response->addHeader("Cache-Control", "max-age=86400"); request->send(response); }); @@ -991,6 +1137,14 @@ void SetupAsyncServer() { request->send(SPIFFS, "/index.html", String(), false, processor); }); + server.on("/live.kml", HTTP_GET, [](AsyncWebServerRequest * request) { + request->send(200, "application/vnd.google-earth.kml+xml", createKMLLive(sonde.ipaddr.c_str())); + }); + + server.on("/dynamic.kml", HTTP_GET, [](AsyncWebServerRequest * request) { + request->send(200, "application/vnd.google-earth.kml+xml", createKMLDynamic()); + }); + server.onNotFound([](AsyncWebServerRequest * request) { if (request->method() == HTTP_OPTIONS) { request->send(200); @@ -1006,10 +1160,6 @@ void SetupAsyncServer() { } }); - // Set up web socket - ws.onEvent(onWsEvent); - server.addHandler(&ws); - // Start server server.begin(); } @@ -1020,18 +1170,10 @@ int fetchWifiIndex(const char *id) { Serial.printf("Match for %s at %d\n", id, i); return i; } - Serial.printf("No match: '%s' vs '%s'\n", id, networks[i].id.c_str()); + //Serial.printf("No match: '%s' vs '%s'\n", id, networks[i].id.c_str()); const char *cfgid = networks[i].id.c_str(); int len = strlen(cfgid); if (strlen(id) > len) len = strlen(id); - Serial.print("SSID: "); - for (int i = 0; i < len; i++) { - Serial.printf("%02x ", id[i]); - } Serial.println(""); - Serial.print("Conf: "); - for (int i = 0; i < len; i++) { - Serial.printf("%02x ", cfgid[i]); - } Serial.println(""); } return -1; } @@ -1137,10 +1279,40 @@ void unkHandler(T nmea) { if (*s == ',') return; /// no new course data int lastCourse = nmea.parseFloat(s, 0, NULL); Serial.printf("Course update: %d\n", lastCourse); + } else if (strcmp(nmea.getMessageID(), "GST") == 0) { + // get horizontal accuracy for android app on devices without gps + // GPGST,time,rms,-,-,-,stdlat,stdlon,stdalt,cs + const char *s = nmea.getSentence(); + while (*s && *s != ',') s++; // #0: GST + if (*s == ',') s++; else return; + while (*s && *s != ',') s++; // #1: time: skip + if (*s == ',') s++; else return; + while (*s && *s != ',') s++; // #1: rms: skip + if (*s == ',') s++; else return; + while (*s && *s != ',') s++; // #1: (-): skip + if (*s == ',') s++; else return; + while (*s && *s != ',') s++; // #1: (-): skip + if (*s == ',') s++; else return; + while (*s && *s != ',') s++; // #1: (-): skip + if (*s == ',') s++; else return; + // stdlat + int stdlat = nmea.parseFloat(s, 1, NULL); + while (*s && *s != ',') s++; + if (*s == ',') s++; else return; + // stdlong + int stdlon = nmea.parseFloat(s, 1, NULL); + // calculate position error as 1-signma horizontal RMS + // I guess that is equivalent to Androids getAccurac()? + int poserr = 0; + if (stdlat < 10000 && stdlon < 10000) { // larger errors: no GPS fix, avoid overflow in * + poserr = (int)(sqrt(0.5 * (stdlat * stdlat + stdlon * stdlon))); + } + //Serial.printf("\nHorizontal accuracy: %d, %d => %.1fm\n", stdlat, stdlon, 0.1*poserr); + gpsPos.accuracy = poserr; } } -#define DEBUG_GPS 1 +//#define DEBUG_GPS static bool gpsCourseOld; static int lastCourse; void gpsTask(void *parameter) { @@ -1152,22 +1324,22 @@ void gpsTask(void *parameter) { //Serial.print(c); if (nmea.process(c)) { gpsPos.valid = nmea.isValid(); - if(gpsPos.valid) { - gpsPos.lon = nmea.getLongitude()*0.000001; - gpsPos.lat = nmea.getLatitude()*0.000001; - long alt = 0; - nmea.getAltitude(alt); - gpsPos.alt=(int)(alt/1000); - gpsPos.course = (int)(nmea.getCourse()/1000); - gpsCourseOld = false; - if(gpsPos.course==0) { - // either north or not new - if(lastCourse!=0) // use old value... - { - gpsCourseOld = true; - gpsPos.course = lastCourse; - } - } + if (gpsPos.valid) { + gpsPos.lon = nmea.getLongitude() * 0.000001; + gpsPos.lat = nmea.getLatitude() * 0.000001; + long alt = 0; + nmea.getAltitude(alt); + gpsPos.alt = (int)(alt / 1000); + gpsPos.course = (int)(nmea.getCourse() / 1000); + gpsCourseOld = false; + if (gpsPos.course == 0) { + // either north or not new + if (lastCourse != 0) // use old value... + { + gpsCourseOld = true; + gpsPos.course = lastCourse; + } + } } #ifdef DEBUG_GPS uint8_t hdop = nmea.getHDOP(); @@ -1181,25 +1353,41 @@ void gpsTask(void *parameter) { #define UBX_SYNCH_1 0xB5 #define UBX_SYNCH_2 0x62 -uint8_t ubx_set9k6[]={UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x8F}; -uint8_t ubx_factorydef[]={UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x09, 13, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0x17, 0x8A }; +uint8_t ubx_set9k6[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x8F}; +uint8_t ubx_factorydef[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x09, 13, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0x17, 0x8A }; +uint8_t ubx_hardreset[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x04, 4, 0, 0xff, 0xff, 0, 0, 0x0C, 0x5D }; +// GPGST: Class 0xF0 Id 0x07 +uint8_t ubx_enable_gpgst[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x01, 3, 0, 0xF0, 0x07, 2, 0x03, 0x1F}; void initGPS() { if (sonde.config.gps_rxd < 0) return; // GPS disabled if (sonde.config.gps_txd >= 0) { // TX enable, thus try setting baud to 9600 and do a factory reset - Serial.println("Trying to reset GPS..."); - Serial2.begin(115200, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); - Serial2.write(ubx_set9k6, sizeof(ubx_set9k6)); - delay(100); - Serial2.begin(38400, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); - Serial2.write(ubx_set9k6, sizeof(ubx_set9k6)); - delay(100); - Serial2.begin(19200, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); - Serial2.write(ubx_set9k6, sizeof(ubx_set9k6)); - delay(100); - Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); - Serial2.write(ubx_factorydef, sizeof(ubx_factorydef)); - delay(1000); + File testfile = SPIFFS.open("/GPSRESET", FILE_READ); + if (testfile && !testfile.isDirectory()) { + testfile.close(); + Serial.println("GPS factory reset..."); + Serial2.begin(115200, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); + Serial2.write(ubx_set9k6, sizeof(ubx_set9k6)); + delay(100); + Serial2.begin(38400, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); + Serial2.write(ubx_set9k6, sizeof(ubx_set9k6)); + delay(100); + Serial2.begin(19200, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); + Serial2.write(ubx_set9k6, sizeof(ubx_set9k6)); + delay(100); + Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); + Serial2.write(ubx_factorydef, sizeof(ubx_factorydef)); + delay(100); + Serial2.write(ubx_hardreset, sizeof(ubx_hardreset)); + delay(5000); + SPIFFS.remove("/GPSRESET"); + } else if (testfile) { + Serial.println("GPS reset file: not found/isdir"); + testfile.close(); + Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); + } + // Enable GPGST messages + Serial2.write(ubx_enable_gpgst, sizeof(ubx_enable_gpgst)); } else { Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd); } @@ -1210,6 +1398,12 @@ void initGPS() { NULL); /* task handle*/ } +const char *getStateStr(int what) { + if(what<0 || what>=(sizeof(mainStateStr)/sizeof(const char *))) + return "--"; + else + return mainStateStr[what]; +} void sx1278Task(void *parameter) { /* new strategy: @@ -1225,13 +1419,12 @@ void sx1278Task(void *parameter) { while (1) { if (rxtask.activate >= 128) { // activating sx1278 background task... - Serial.printf("rx task: activate=%d mainstate=%d\n", rxtask.activate, rxtask.mainState); + Serial.printf("RXtask: start DECODER for sonde %d (was %s)\n", rxtask.activate&0x7f, getStateStr(rxtask.mainState)); rxtask.mainState = ST_DECODER; rxtask.currentSonde = rxtask.activate & 0x7F; - Serial.println("rx task: calling sonde.setup()"); sonde.setup(); } else if (rxtask.activate != -1) { - Serial.printf("rx task: activate=%d mainstate=%d\n", rxtask.activate, rxtask.mainState); + Serial.printf("RXtask: start %s (was %s)\n", getStateStr(rxtask.activate), getStateStr(rxtask.mainState)); rxtask.mainState = rxtask.activate; } rxtask.activate = -1; @@ -1479,7 +1672,7 @@ extern esp_err_t heap_caps_register_failed_alloc_callback(esp_alloc_failed_hook_ void heap_caps_alloc_failed_hook(size_t requested_size, uint32_t caps, const char *function_name) { - printf("%s was called but failed to allocate %d bytes with 0x%X capabilities. \n",function_name, requested_size, caps); + printf("%s was called but failed to allocate %d bytes with 0x%X capabilities. \n", function_name, requested_size, caps); } #endif @@ -1540,7 +1733,7 @@ void setup() // NOT TTGO v1 (fingerprint 64) or Heltec v1/v2 board (fingerprint 4) // and NOT TTGO Lora32 v2.1_1.6 (fingerprint 31/63) - if ( ( (sonde.fingerprint&(64+31)) != 31) && ((sonde.fingerprint & 16) == 16) ) { + if ( ( (sonde.fingerprint & (64 + 31)) != 31) && ((sonde.fingerprint & 16) == 16) ) { // FOr T-Beam 1.0 for (int i = 0; i < 10; i++) { // try multiple times Wire.begin(21, 22); @@ -1564,12 +1757,12 @@ void setup() axp.adc1Enable(AXP202_VBUS_VOL_ADC1, 1); axp.adc1Enable(AXP202_VBUS_CUR_ADC1, 1); axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1); - if(sonde.config.button2_axp) { + if (sonde.config.button2_axp) { pinMode(PMU_IRQ, INPUT_PULLUP); attachInterrupt(PMU_IRQ, [] { pmu_irq = true; }, FALLING); - //axp.enableIRQ(AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ, 1); + //axp.enableIRQ(AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ, 1); axp.enableIRQ( AXP202_PEK_LONGPRESS_IRQ | AXP202_PEK_SHORTPRESS_IRQ, 1 ); axp.clearIRQ(); } @@ -1625,7 +1818,7 @@ void setup() sonde.clearDisplay(); setupWifiList(); - Serial.printf("before disp.initFromFile... layouts is %p", disp.layouts); + Serial.printf("before disp.initFromFile... layouts is %p\n", disp.layouts); disp.initFromFile(sonde.config.screenfile); Serial.printf("disp.initFromFile... layouts is %p", disp.layouts); @@ -1779,39 +1972,47 @@ static const char *action2text(uint8_t action) { #define RDZ_DATA_LEN 128 void parseGpsJson(char *data) { - char *key = NULL; - char *value = NULL; - // very simple json parser: look for ", then key, then ", then :, then number, then , or } or \0 - for(int i=0; i