From 0a625f1283703b5b8a77196b0c77d65e5d81d621 Mon Sep 17 00:00:00 2001 From: "Hansi, dl9rdz" Date: Sun, 24 Jan 2021 13:04:17 +0100 Subject: [PATCH] better T-Beam 1.1 autodetect --- RX_FSK/RX_FSK.ino | 171 +++++++++++++++++++++++++--- RX_FSK/version.h | 2 +- libraries/SondeLib/Display.cpp | 47 ++++---- libraries/SondeLib/Display.h | 14 ++- libraries/SondeLib/Sonde.cpp | 21 +++- libraries/SondeLib/autodetect-infos | 9 ++ 6 files changed, 216 insertions(+), 48 deletions(-) diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index ca7883c..e7e1c1a 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -48,9 +48,12 @@ boolean connected = false; WiFiUDP udp; WiFiClient client; -// KISS over TCP für communicating with APRSdroid +// KISS over TCP for communicating with APRSdroid WiFiServer tncserver(14580); WiFiClient tncclient; +// JSON over TCP for communicating with my kotlin andoird test stuff +WiFiServer rdzserver(14570); +WiFiClient rdzclient; unsigned long lastMqttUptime = 0; boolean mqttEnabled; @@ -1123,8 +1126,6 @@ MicroNMEA nmea(buffer, sizeof(buffer)); -int lastCourse = 0; - /// Arrg. MicroNMEA changes type definition... so lets auto-infer type template //void unkHandler(const MicroNMEA& nmea) { @@ -1134,11 +1135,14 @@ void unkHandler(T nmea) { while (*s && *s != ',') s++; if (*s == ',') s++; else return; if (*s == ',') return; /// no new course data - lastCourse = nmea.parseFloat(s, 0, NULL); + int lastCourse = nmea.parseFloat(s, 0, NULL); Serial.printf("Course update: %d\n", lastCourse); } } -//#define DEBUG_GPS 1 + +#define DEBUG_GPS 1 +static bool gpsCourseOld; +static int lastCourse; void gpsTask(void *parameter) { nmea.setUnknownSentenceHandler(unkHandler); @@ -1147,16 +1151,27 @@ void gpsTask(void *parameter) { char c = Serial2.read(); //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; + } + } + } #ifdef DEBUG_GPS - Serial.print(nmea.getSentence()); - long lat = nmea.getLatitude(); - long lon = nmea.getLongitude(); - long alt = -1; - bool b = nmea.getAltitude(alt); - bool valid = nmea.isValid(); - int course = nmea.getCourse() / 1000; uint8_t hdop = nmea.getHDOP(); - Serial.printf(" =>: valid: %d N %ld E %ld alt %ld (%d) course:%d dop:%d\n", valid ? 1 : 0, lat, lon, alt, b, c, hdop); + Serial.printf(" =>: valid: %d N %f E %f alt %d course:%d dop:%d\n", gpsPos.valid ? 1 : 0, gpsPos.lat, gpsPos.lon, gpsPos.alt, gpsPos.course, hdop); #endif } } @@ -1549,6 +1564,7 @@ void setup() axp.adc1Enable(AXP202_VBUS_VOL_ADC1, 1); axp.adc1Enable(AXP202_VBUS_CUR_ADC1, 1); axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1); + axp.setChgLEDMode(AXP20X_LED_BLINK_4HZ); if(sonde.config.button2_axp) { pinMode(PMU_IRQ, INPUT_PULLUP); attachInterrupt(PMU_IRQ, [] { @@ -1760,6 +1776,48 @@ static const char *action2text(uint8_t action) { } return text; } + +#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=RDZ_DATA_LEN) { + // parse GPS position from phone + rdzData[rdzDataPos] = c; + if(rdzDataPos>2) parseGpsJson(rdzData); + rdzDataPos = 0; + } + else { + rdzData[rdzDataPos++] = c; + } + } + Serial.println(""); + } // wifi (axudp) or bluetooth (bttnc) active => send packet - if ((res & 0xff) == 0 && (connected || tncclient.connected() )) { + if ((res & 0xff) == 0 && (connected || tncclient.connected() || rdzclient.connected() )) { //Send a packet with position information // first check if ID and position lat+lonis ok SondeInfo *s = &sonde.sondeList[rxtask.receiveSonde]; @@ -1825,6 +1906,65 @@ void loopDecoder() { Serial.print("sending: "); Serial.println(raw); tncclient.write(raw, rawlen); } + if (rdzclient.connected()) { + Serial.println("Sending position via TCP as rdzJSON"); + char raw[1024]; + int len = snprintf(raw, 1024, "{" + "\"active\": %d," + "\"freq\": %.2f," + "\"id\": \"%s\"," + "\"ser\": \"%s\"," + "\"validId\": %d," + "\"launchsite\": \"%s\"," + "\"lat\": %.5f," + "\"lon\": %.5f," + "\"alt\": %.1f," + "\"vs\": %.1f," + "\"hs\": %.1f," + "\"dir\": %.1f," + "\"sats\": %d," + "\"validPos\": %d," + "\"time\": %d," + "\"sec\": %d," + "\"frame\": %d," + "\"validTime\": %d," + "\"rssi\": %d," + "\"afc\": %d," + "\"rxStat\": \"%s\"," + "\"launchKT\": %d," + "\"burstKT\": %d," + "\"countKT\": %d," + "\"crefKT\": %d" + "}\n", + (int)s->active, + s->freq, + s->id, + s->ser, + (int)s->validID, + s->launchsite, + s->lat, + s->lon, + s->alt, + s->vs, + s->hs, + s->dir, + s->sats, + s->validPos, + s->time, + s->sec, + s->frame, + (int)s->validTime, + s->rssi, + s->afc, + s->rxStat, + s->launchKT, + s->burstKT, + s->countKT, + s->crefKT + ); + + rdzclient.write(raw, len>1024?1024:len); + } } // send to MQTT if enabled @@ -1926,8 +2066,11 @@ void enableNetwork(bool enable) { SetupAsyncServer(); udp.begin(WiFi.localIP(), LOCALUDPPORT); MDNS.addService("http", "tcp", 80); + MDNS.addService("kisstnc", "tcp", 14580); + MDNS.addService("jsonrdz", "tcp", 14570); if (sonde.config.kisstnc.active) { tncserver.begin(); + rdzserver.begin(); } if (sonde.config.mqtt.active && strlen(sonde.config.mqtt.host) > 0) { diff --git a/RX_FSK/version.h b/RX_FSK/version.h index 311a1e6..150bffa 100644 --- a/RX_FSK/version.h +++ b/RX_FSK/version.h @@ -1,4 +1,4 @@ const char *version_name = "rdzTTGOsonde"; -const char *version_id = "devel20201230b"; +const char *version_id = "devel20210124"; const int SPIFFS_MAJOR=2; const int SPIFFS_MINOR=8; diff --git a/libraries/SondeLib/Display.cpp b/libraries/SondeLib/Display.cpp index ea53154..00a261b 100644 --- a/libraries/SondeLib/Display.cpp +++ b/libraries/SondeLib/Display.cpp @@ -19,12 +19,11 @@ extern const char *version_id; extern Sonde sonde; -extern MicroNMEA nmea; - extern AXP20X_Class axp; extern bool axp192_found; extern SemaphoreHandle_t axpSemaphore; +struct GpsPos gpsPos; SPIClass spiDisp(HSPI); @@ -1233,6 +1232,7 @@ void Display::drawKilltimer(DispEntry *de) { extern int lastCourse; // from RX_FSK.ino void Display::calcGPS() { // base data +#if 0 #if FAKEGPS gpsValid = true; gpsLat = 48.9; @@ -1257,12 +1257,13 @@ static int tmpc=0; gpsCourse = lastCourse; } } +#endif #endif // distance - if( gpsValid && (sonde.si()->validPos&0x03)==0x03 && (layout->usegps&GPSUSE_DIST)) { - float lat1 = nmea.getLatitude()*0.000001; + if( gpsPos.valid && (sonde.si()->validPos&0x03)==0x03 && (layout->usegps&GPSUSE_DIST)) { + float lat1 = gpsPos.lat; float lat2 = sonde.si()->lat; - float x = radians(nmea.getLongitude()*0.000001-sonde.si()->lon) * cos( radians((lat1+lat2)/2) ); + float x = radians(gpsPos.lon-sonde.si()->lon) * cos( radians((lat1+lat2)/2) ); float y = radians(lat2-lat1); float d = sqrt(x*x+y*y)*EARTH_RADIUS; gpsDist = (int)d; @@ -1270,17 +1271,17 @@ static int tmpc=0; gpsDist = -1; } // bearing - if( gpsValid && (sonde.si()->validPos&0x03)==0x03 && (layout->usegps&GPSUSE_BEARING)) { - float lat1 = radians(gpsLat); + if( gpsPos.valid && (sonde.si()->validPos&0x03)==0x03 && (layout->usegps&GPSUSE_BEARING)) { + float lat1 = radians(gpsPos.lat); float lat2 = radians(sonde.si()->lat); - float lon1 = radians(gpsLon); + float lon1 = radians(gpsPos.lon); float lon2 = radians(sonde.si()->lon); float y = sin(lon2-lon1)*cos(lat2); float x = cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(lon2-lon1); float dir = atan2(y, x)/PI*180; if(dir<0) dir+=360; gpsDir = (int)dir; - gpsBear = gpsDir - gpsCourse; + gpsBear = gpsDir - gpsPos.course; if(gpsBear < 0) gpsBear += 360; if(gpsBear >= 360) gpsBear -= 360; } else { @@ -1288,39 +1289,39 @@ static int tmpc=0; gpsBear = -1; } - DebugPrintf(DEBUG_DISPLAY, "GPS data: valid%d GPS at %f,%f (alt=%d,cog=%d); sonde at dist=%d, dir=%d rel.bear=%d\n",gpsValid?1:0, - gpsLat, gpsLon, gpsAlt, gpsCourse, gpsDist, gpsDir, gpsBear); + DebugPrintf(DEBUG_DISPLAY, "GPS data: valid%d GPS at %f,%f (alt=%d,cog=%d); sonde at dist=%d, dir=%d rel.bear=%d\n",gpsPos.valid?1:0, + gpsPos.lat, gpsPos.lon, gpsPos.alt, gpsPos.course, gpsDist, gpsDir, gpsBear); } void Display::drawGPS(DispEntry *de) { - if(sonde.config.gps_rxd<0) return; + // TODO: FIXME: ??? if(sonde.config.gps_rxd<0) return; rdis->setFont(de->fmt); switch(de->extra[0]) { case 'V': { // show if GPS location is valid - uint8_t *tile = disp.gpsValid?gps_tile:nogps_tile; + uint8_t *tile = gpsPos.valid?gps_tile:nogps_tile; rdis->drawTile(de->x, de->y, 1, tile); } break; case 'O': // GPS long - snprintf(buf, 16, "%2.5f", disp.gpsLon); + snprintf(buf, 16, "%2.5f", gpsPos.lon); drawString(de,buf); break; case 'A': // GPS lat - snprintf(buf, 16, "%2.5f", disp.gpsLat); + snprintf(buf, 16, "%2.5f", gpsPos.lat); drawString(de,buf); break; case 'H': // GPS alt - snprintf(buf, 16, "%4dm", disp.gpsAlt); + snprintf(buf, 16, "%4dm", gpsPos.alt); drawString(de,buf); break; case 'C': // GPS Course over ground - snprintf(buf, 4, "%3d", disp.gpsCourse); + snprintf(buf, 4, "%3d", gpsPos.course); drawString(de, buf); break; case 'D': @@ -1330,7 +1331,7 @@ void Display::drawGPS(DispEntry *de) { if( (sonde.si()->validPos&0x03)!=0x03 ) { snprintf(buf, 16, "no pos "); if(de->extra && *de->extra=='5') buf[5]=0; - } else if(!disp.gpsValid) { + } else if(!gpsPos.valid) { snprintf(buf, 16, "no gps "); if(de->extra && *de->extra=='5') buf[5]=0; } else { @@ -1350,7 +1351,7 @@ void Display::drawGPS(DispEntry *de) { break; case 'I': // dIrection - if( (!disp.gpsValid) || ((sonde.si()->validPos&0x03)!=0x03 ) ) { + if( (!gpsPos.valid) || ((sonde.si()->validPos&0x03)!=0x03 ) ) { drawString(de, "---"); break; } @@ -1362,7 +1363,7 @@ void Display::drawGPS(DispEntry *de) { break; case 'B': // relative bearing - if( (!disp.gpsValid) || ((sonde.si()->validPos&0x03)!=0x03 ) ) { + if( (!gpsPos.valid) || ((sonde.si()->validPos&0x03)!=0x03 ) ) { drawString(de, "---"); break; } @@ -1392,15 +1393,15 @@ void Display::drawGPS(DispEntry *de) { bool rxgood = (sonde.si()->rxStat[0]==0); int angN, angA, angB; // angle of north, array, bullet int validA, validB; // 0: no, 1: yes, -1: old - if(circinfo->arr=='C') { angA=disp.gpsCourse; validA=disp.gpsCourseOld?-1:1; } + if(circinfo->arr=='C') { angA=gpsPos.course; validA=disp.gpsCourseOld?-1:1; } else { angA=disp.gpsDir; validA=sonde.si()->validPos?(rxgood?1:-1):0; } - if(circinfo->bul=='C') { angB=disp.gpsCourse; validB=disp.gpsCourseOld?-1:1; } + if(circinfo->bul=='C') { angB=gpsPos.course; validB=disp.gpsCourseOld?-1:1; } else { angB=disp.gpsDir; validB=sonde.si()->validPos?(rxgood?1:-1):0; } if(circinfo->top=='N') { angN = 0; } else { //if (circinfo->top=='C') { - angN = 360-disp.gpsCourse; + angN = 360-gpsPos.course; angA += angN; if(angA>=360) angA-=360; angB += angN; if(angB>=360) angB-=360; } diff --git a/libraries/SondeLib/Display.h b/libraries/SondeLib/Display.h index b76ef32..0286f89 100644 --- a/libraries/SondeLib/Display.h +++ b/libraries/SondeLib/Display.h @@ -10,6 +10,15 @@ #include #include +struct GpsPos { + double lat; + double lon; + int alt; + int course; + int valid; +}; +extern struct GpsPos gpsPos; + #define WIDTH_AUTO 9999 struct DispEntry { int16_t y; @@ -123,11 +132,8 @@ private: static void circ(uint16_t *bm, int16_t w, int16_t x0, int16_t y0, int16_t r, uint16_t fg, boolean fill, uint16_t bg); static int countEntries(File f); void calcGPS(); - boolean gpsValid; - float gpsLat, gpsLon; - int gpsAlt; int gpsDist; // -1: invalid - int gpsCourse, gpsDir, gpsBear; // 0..360; -1: invalid + int gpsDir, gpsBear; // 0..360; -1: invalid boolean gpsCourseOld; static const int LINEBUFLEN{ 255 }; static char lineBuf[LINEBUFLEN]; diff --git a/libraries/SondeLib/Sonde.cpp b/libraries/SondeLib/Sonde.cpp index f716cd5..bf1ca9e 100644 --- a/libraries/SondeLib/Sonde.cpp +++ b/libraries/SondeLib/Sonde.cpp @@ -19,16 +19,18 @@ const char *evstring[]={"NONE", "KEY1S", "KEY1D", "KEY1M", "KEY1L", "KEY2S", "KE const char *RXstr[]={"RX_OK", "RX_TIMEOUT", "RX_ERROR", "RX_UNKNOWN"}; -int fingerprintValue[]={ 17, 31, 64, 4, 55, 48, 23, 128+23, -1 }; +int fingerprintValue[]={ 17, 31, 64, 4, 55, 48, 23, 128+23, 119, 128+119, -1 }; const char *fingerprintText[]={ "TTGO T-Beam (new version 1.0), I2C not working after powerup, assuming 0.9\" OLED@21,22", "TTGO LORA32 v2.1_1.6 (0.9\" OLED@21,22)", "TTGO LORA v1.0 (0.9\" OLED@4,15)", "Heltec v1/v2 (0.9\"OLED@4,15)", - "TTGO T-Beam (old version), 0.9\" OLED@21,22", - "TTGO T-Beam (old version), SPI TFT@4,21,22", - "TTGO T-Beam (new version 1.0), 0.9\" OLED@21,22", - "TTGO T-Beam (new version 1.0), SPI TFT@4,13,14", + "TTGO T-Beam (V0.7), 0.9\" OLED@21,22", + "TTGO T-Beam (V0.7), SPI TFT@4,21,22", + "TTGO T-Beam (V1.0), 0.9\" OLED@21,22", + "TTGO T-Beam (V1.0), SPI TFT@4,13,14", + "TTGO T-Beam (V1.1), 0.9\" OLED@21,22", + "TTGO T-Beam (V1.1), SPI TFT@4,13,14", }; /* global variables from RX_FSK.ino */ @@ -97,8 +99,15 @@ void Sonde::defaultConfig() { config.oled_sda = 21; config.oled_scl = 22; if(initlevels[17]==0) { // T-Beam - if(initlevels[12]==0) { // T-Beam v1.0 + int tbeam=7; + if(initlevels[12]==0) { + tbeam = 10; Serial.println("Autoconfig: looks like T-Beam 1.0 board"); + } else if ( initlevels[4]==1 && initlevels[12]==1 ) { + tbeam = 11; + Serial.println("Autoconfig: looks like T-Beam 1.1 board"); + } + if(tbeam == 10 || tbeam == 11) { // T-Beam v1.0 or T-Beam v1.1 config.button_pin = 38; config.button2_pin = 15 + 128; //T4 + 128; // T4 = GPIO13 // Maybe in future use as default only PWR as button2? diff --git a/libraries/SondeLib/autodetect-infos b/libraries/SondeLib/autodetect-infos index 02cf2de..fe23d05 100644 --- a/libraries/SondeLib/autodetect-infos +++ b/libraries/SondeLib/autodetect-infos @@ -30,6 +30,15 @@ TTGO T-Beam 1.0 with OLED display => fingerprint 0010111 => 23 0:1 1:0 2:0 3:1 4:0 5:1 6:0 7:1 8:0 9:1 10:1 11:1 12:0 13:0 14:1 15:1 16:1 17:0 18:0 19:0 20:0 21:1 22:1 23:1 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:0 32:0 33:0 34:0 35:0 36:0 37:0 38:0 0:4 1:4 2:0 3:4 4:0 5:4 6:0 7:4 8:0 9:4 10:4 11:4 12:0 13:0 14:4 15:4 16:4 17:0 18:0 19:0 20:0 21:4 22:4 23:4 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:0 32:0 33:0 34:0 35:0 36:0 37:0 38:0 (before setup) +TTGO T-Team 1.0 with IL9225 TFT => fingerprint 23 +0:1 1:0 2:0 3:1 4:0 5:1 6:0 7:1 8:0 9:1 10:1 11:1 12:0 13:0 14:1 15:1 16:1 17:0 18:0 19:0 20:0 21:1 22:1 23:1 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:0 32:0 33:0 34:0 35:0 36:0 37:0 38:0 +0:1 1:1 2:0 3:1 4:0 5:1 6:0 7:1 8:0 9:1 10:1 11:1 12:0 13:0 14:1 15:1 16:1 17:0 18:0 19:0 20:0 21:1 22:1 23:1 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:0 32:0 33:0 34:0 35:0 36:0 37:0 38:0 (before setup) + + vs 0010111 +T-Beam 1.1 seems to be different: 1110111 +GPIO4 = 1 (additional pullup) => +64 +GPIO12 = 1 (maybe additional pullup) => +32 + 1 Fingerprint GPIOs: 4, 12, 16, 17, 21, 22, 23,