better T-Beam 1.1 autodetect

pull/63/head
Hansi, dl9rdz 2021-01-24 13:04:17 +01:00
rodzic 82db61c91f
commit 0a625f1283
6 zmienionych plików z 216 dodań i 48 usunięć

Wyświetl plik

@ -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<typename T>
//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; i++) {
if(key==NULL) {
if(data[i]!='"') continue;
key=data+i+1;
i+=2;
continue;
}
if(value==NULL) {
if(data[i]!=':') continue;
value = data+i+1;
i += 2;
continue;
}
if(data[i]==',' || data[i]=='}' || data[i]==0) {
// get value
double val = strtod(value,NULL);
// get data
if(strncmp(key,"lat",3)==0) { gpsPos.lat = val; }
else if(strncmp(key,"lon",3)==0) { gpsPos.lon = val; }
else if(strncmp(key,"alt",3)==0) { gpsPos.alt = (int)val; }
else if(strncmp(key,"course",6)==0) { gpsPos.course = (int)val; }
gpsPos.valid = true;
// next item:
if(data[i]!=',') break;
key = NULL;
value = NULL;
}
}
Serial.printf("Parse result: lat=%f, lon=%f, alt=%d, valid=%d\n", gpsPos.lat, gpsPos.lon, gpsPos.alt, gpsPos.valid);
}
static char rdzData[RDZ_DATA_LEN];
static int rdzDataPos = 0;
void loopDecoder() {
// sonde knows the current type and frequency, and delegates to the right decoder
uint16_t res = sonde.waitRXcomplete();
@ -1801,8 +1859,31 @@ void loopDecoder() {
}
Serial.println("");
}
if (!rdzclient.connected()) {
rdzclient = rdzserver.available();
if(rdzclient.connected()) {
Serial.println("RDZ JSON socket: new connection");
}
}
if(rdzclient.available()) {
Serial.print("RDZ JSON socket: received ");
while(rdzclient.available()) {
char c = (char)rdzclient.read();
Serial.print(c);
if(c=='\n'||c=='}'||rdzDataPos>=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) {

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -10,6 +10,15 @@
#include <U8x8lib.h>
#include <SPIFFS.h>
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];

Wyświetl plik

@ -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?

Wyświetl plik

@ -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,