diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index c092738..6ae16ce 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -901,14 +901,15 @@ void initTouch() { char buffer[85]; MicroNMEA nmea(buffer, sizeof(buffer)); +int lastCourse=0; void unkHandler(const MicroNMEA& nmea) { if (strcmp(nmea.getMessageID(), "VTG") == 0) { const char *s = nmea.getSentence(); while (*s && *s != ',') s++; if (*s == ',') s++; else return; if (*s == ',') return; /// no new course data - int course = nmea.parseFloat(s, 0, NULL); - Serial.printf("Course update: %d\n", course); + lastCourse = nmea.parseFloat(s, 0, NULL); + Serial.printf("Course update: %d\n", lastCourse); } } void gpsTask(void *parameter) { @@ -1067,16 +1068,15 @@ int getKeyPress() { KeyPress p = button1.pressed; button1.pressed = KP_NONE; int x = digitalRead(button1.pin); - Serial.printf("Debug: bdd1=%ld, bdd2=%ld\b", bdd1, bdd2); - - Serial.printf("button1 press (dbl:%d) (now:%d): %d at %ld (%d)\n", button1.doublepress, x, p, button1.keydownTime, button1.numberKeyPresses); + //Serial.printf("Debug: bdd1=%ld, bdd2=%ld\b", bdd1, bdd2); + //Serial.printf("button1 press (dbl:%d) (now:%d): %d at %ld (%d)\n", button1.doublepress, x, p, button1.keydownTime, button1.numberKeyPresses); return p; } int getKey2Press() { KeyPress p = button2.pressed; button2.pressed = KP_NONE; - Serial.printf("button2 press: %d at %ld (%d)\n", p, button2.keydownTime, button2.numberKeyPresses); + //Serial.printf("button2 press: %d at %ld (%d)\n", p, button2.keydownTime, button2.numberKeyPresses); return p; } int hasKeyPress() { @@ -1088,8 +1088,10 @@ int getKeyPressEvent() { p = getKey2Press(); if (p == KP_NONE) return EVT_NONE; + Serial.printf("Key 2 was pressed [%d]\n", p+4); return p + 4; } + Serial.printf("Key 1 was pressed [%d]\n", p); return p; /* map KP_x to EVT_KEY1_x / EVT_KEY2_x*/ } @@ -1207,6 +1209,8 @@ void setup() axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON); axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); axp.setDCDC1Voltage(3300); + axp.adc1Enable(AXP202_VBUS_VOL_ADC1, 1); + axp.adc1Enable(AXP202_VBUS_CUR_ADC1, 1); pinMode(PMU_IRQ, INPUT_PULLUP); attachInterrupt(PMU_IRQ, [] { pmu_irq = true; @@ -1469,6 +1473,7 @@ void loopDecoder() { Serial.println("updateDisplay started"); if (forceReloadScreenConfig) { disp.initFromFile(); + sonde.clearDisplay(); forceReloadScreenConfig = false; } sonde.updateDisplay(); @@ -2088,4 +2093,5 @@ void loop() { sonde.updateDisplay(); lastDisplay = currentDisplay; } + Serial.printf("Unused stack: %d\n", uxTaskGetStackHighWaterMark(0)); } diff --git a/RX_FSK/data/screens.txt b/RX_FSK/data/screens.txt index 936bf88..bd35450 100644 --- a/RX_FSK/data/screens.txt +++ b/RX_FSK/data/screens.txt @@ -40,9 +40,18 @@ # S launch site # Mx telemetry value x (t temp p preassure h hyg) # Gx GPS-related data -# raw data from GPS: GL, GO, GA, GC: Latitude, lOngitude, Altutide, Course +# raw data from GPS: GA, GO, GH, GC: LAtitude, lOngitude, Altutide(Height), Course over ground # relative to sonde: GD, GI, GB: Distance, dIrection (absolute), relative Bearing +# G0 GPS circle diagram e.g. 3,5=g0NCS,50,ff0000,000033,5,ffff00,4,ffffff +# "N" (what is on top: N=north C=course) +# "C" (where does the arrow point to: C=course, S=sonde) +# "S" (what is shown by the bullet: C=course, S=sonde) +# 50: circle radius, followed by fg and bg color +# 5: bullet radius, followed by fg color +# 4: arrow width, followed by fg color # R RSSI +# B battery(T-Beam 1.0) S=status V=Batt.Volt C=charge current D=discharge current +# U=USB volt I=USB current T=IC temp # # fonts=x,y can be used to select font (x=small, y=large) for all items below # for SSD1306, x and y can be used to select one of those fonts: @@ -229,4 +238,58 @@ color=FFFFFF 7,2,6=gD 7,12=gI +############ +@PeilungTFT +timer=-1,-1,20000 +key1action=+,0,F,W +key2action=>,#,#,# +timeaction=#,#,# +color=ffff00,000033 +color=bbbbbb,000000 +0,2=xN Top: +0,8=xCourse Top: +color=ffff00,000033 +1,0=g0NCS,48,ffff00,000044,6,33ff33,5,eeaa00 +1,8=g0CCS,48,ffff00,000044,6,55ff55,5,eeaa00 +color=ffffff,000000 +6,0=xDirection: +6,8,4=gI +7,0=xCOG: +7,4,4=gC +7,8=xturn: +7,12,4=gB + +############ +@GPSdataTFT +timer=-1,-1,20000 +key1action=+,0,F,W +key2action=>,#,#,# +timeaction=#,#,# +0,0=xOn-board GPS: +1,0,8=gA +2,0,8=gO +3,0,8=gH +4,0,8=gC +5,0=xGPS vs Sonde: +6,0,8=gD +7,0,8=gI +7,8,8=gB + +############ +@BatteryTFT +timer=-1,-1,20000 +key1action=+,0,F,W +key2action=>,#,#,# +timeaction=#,#,# +0,0=xBattery status: +0,14=bS +1,0=xBatt: +1,5,5=bVV +2,0,16=bCmA(charging) +3,0,16=bDmA(discharging) +4.4,0=xUSB: +4.4,5,5=bUV +5.4,0,10=bImA +6.4,0=xTemp: +6.4,5,5=bT C diff --git a/libraries/SX1278FSK/SX1278FSK.cpp b/libraries/SX1278FSK/SX1278FSK.cpp index 7bff0a0..abf9c93 100644 --- a/libraries/SX1278FSK/SX1278FSK.cpp +++ b/libraries/SX1278FSK/SX1278FSK.cpp @@ -726,8 +726,10 @@ uint8_t SX1278FSK::receivePacketTimeout(uint32_t wait, byte *data) if(di==1 || di==290 ) { int rssi=getRSSI(); int afc=getAFC(); +#if 0 Serial.printf("Test(%d): RSSI=%d", rxtask.currentSonde, rssi/2); Serial.print("Test: AFC="); Serial.println(afc); +#endif sonde.sondeList[rxtask.currentSonde].rssi = rssi; sonde.sondeList[rxtask.currentSonde].afc = afc; if(rxtask.receiveResult==0xFFFF) diff --git a/libraries/SondeLib/Display.cpp b/libraries/SondeLib/Display.cpp index 2778e11..9e08967 100644 --- a/libraries/SondeLib/Display.cpp +++ b/libraries/SondeLib/Display.cpp @@ -1,7 +1,7 @@ #include #include #include - +#include #include #include "Display.h" #include "Sonde.h" @@ -19,6 +19,9 @@ extern Sonde sonde; extern MicroNMEA nmea; +extern AXP20X_Class axp; +extern bool axp192_found; + SPIClass spiDisp(HSPI); const char *sondeTypeStr[5] = { "DFM6", "DFM9", "RS41", "RS92" }; @@ -243,6 +246,9 @@ void U8x8Display::drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr) void U8x8Display::drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h) { // not supported } +void U8x8Display::drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color, bool fill) { + // not supported (yet) +} void U8x8Display::welcome() { u8x8->clear(); @@ -360,9 +366,7 @@ void ILI9225Display::getDispSize(uint8_t *height, uint8_t *width, uint8_t *lines void ILI9225Display::drawString(uint8_t x, uint8_t y, const char *s, int16_t width, uint16_t fg, uint16_t bg) { int16_t w,h; boolean alignright=false; - Serial.printf("drawString: width=%d\n", width); if(findex<3) { // standard font - //////////////tft->drawText(x...); Serial.printf("Simple Text %s at %d,%d [%d]\n", s, x, y, width); tft->drawText(x, y, s, fg); return; @@ -379,7 +383,7 @@ void ILI9225Display::drawString(uint8_t x, uint8_t y, const char *s, int16_t wid if(findex-3>=ngfx) findex=3; tft->fillRectangle(x, y, x + width, y + gfxoffsets[findex-3].yclear, bg); - Serial.printf("GFX Text %s at %d,%d+%d in color %x, width=%d\n", s, x, y, gfxoffsets[findex-3].yofs, fg, width); + Serial.printf("GFX Text %s at %d,%d+%d in color %x, width=%d (w=%d)\n", s, x, y, gfxoffsets[findex-3].yofs, fg, width, w); if(alignright) { tft->drawGFXText(x + width - w, y + gfxoffsets[findex-3].yofs, s, fg); } else { @@ -405,6 +409,13 @@ void ILI9225Display::drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_p #endif } +void ILI9225Display::drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color, boolean fill) { + if(fill) + tft->fillTriangle(x1, y1, x2, y2, x3, y3, color); + else + tft->drawTriangle(x1, y1, x2, y2, x3, y3, color); +} + void ILI9225Display::drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h) { tft->drawBitmap(x1, y1, bitmap, w, h); } @@ -510,12 +521,24 @@ Display::Display() { #define DISP_ACTIONS_N 12 #define DISP_TIMEOUTS_N 3 -void Display::freeLayouts() { - if(layouts==staticLayouts) return; +void Display::replaceLayouts(DispInfo *newlayouts, int nnew) { + if(nnew<1) return; // no new layouts => ignore + + // remember old layouts DispInfo *old = layouts; - layouts=staticLayouts; - setLayout(0); - delay(500); // Make it unlikely that anyone else is still using previous layouts + + // assign new layouts and current layout + Serial.printf("replaceLayouts: idx=%d n(new)=%d\n", layoutIdx, nLayouts); + layouts = newlayouts; + nLayouts = nnew; + if(layoutIdx >= nLayouts) layoutIdx = 0; + layout = layouts+layoutIdx; + + // Make it unlikely that anyone else is still using previous layouts + delay(500); + + // and release memory not used any more + if(old==staticLayouts) return; for(int i=0; i>19) << 11 | ((col>>10)&0x3F) << 5 | ((col>>3)&0x1F); +} +uint16_t encodeColor(char *colstr) { + uint32_t col; + int res=sscanf(colstr, "%" SCNx32, &col); + if(res!=1) return 0xffff; + return encodeColor(col); +} + void Display::parseDispElement(char *text, DispEntry *de) { char type = *text; @@ -591,12 +624,36 @@ void Display::parseDispElement(char *text, DispEntry *de) if(text[1]=='0') { // extended configuration for arrow... struct CircleInfo *circinfo = (struct CircleInfo *)malloc(sizeof(struct CircleInfo)); +#if 1 circinfo->type = '0'; - circinfo->radius = atoi(text+2); - circinfo->brad = 3; - circinfo->bcol = 0xffff; - circinfo->acol = 0xffff; - circinfo->awidth = 4; + circinfo->top = text[2]; + circinfo->arr = text[3]; + circinfo->bul = text[4]; + char *ptr=text+5; + while(*ptr && *ptr!=',') ptr++; ptr++; + // next: radius + circinfo->radius = atoi(ptr); + while(*ptr && *ptr!=',') ptr++; ptr++; + circinfo->fgcol = encodeColor(ptr); + while(*ptr && *ptr!=',') ptr++; ptr++; + circinfo->bgcol = encodeColor(ptr); +#else + circinfo->type = '0'; + circinfo->top = 'N'; + circinfo->bul = 'S'; + circinfo->arr = 'C'; + circinfo->radius = 50; + circinfo->fgcol = 0xfe80; + circinfo->bgcol = 0x0033; +#endif + while(*ptr && *ptr!=',') ptr++; ptr++; + circinfo->awidth = atoi(ptr); + while(*ptr && *ptr!=',') ptr++; ptr++; + circinfo->acol = encodeColor(ptr); + while(*ptr && *ptr!=',') ptr++; ptr++; + circinfo->brad = atoi(ptr); + while(*ptr && *ptr!=',') ptr++; ptr++; + circinfo->bcol = encodeColor(ptr); de->extra = (char *)circinfo; } else { de->extra = strdup(text+1); @@ -609,6 +666,10 @@ void Display::parseDispElement(char *text, DispEntry *de) de->func = disp.drawText; de->extra = strdup(text+1); break; + case 'b': + de->func = disp.drawBatt; + de->extra = strdup(text+1); + break; default: Serial.printf("Unknown element: %c\n", type); break; @@ -657,11 +718,9 @@ void Display::initFromFile() { File d = SPIFFS.open("/screens.txt", "r"); if(!d) return; - freeLayouts(); DispInfo *newlayouts = (DispInfo *)malloc(MAXSCREENS * sizeof(DispInfo)); if(!newlayouts) { - Serial.println("Init from file: FAILED, using static layouts"); - layouts = staticLayouts; + Serial.println("Init from file: FAILED, not updating layouts"); return; } memset(newlayouts, 0, MAXSCREENS * sizeof(DispInfo)); @@ -674,6 +733,7 @@ void Display::initFromFile() { int entrysize; Serial.printf("Reading from /screens.txt. available=%d\n",d.available()); while(d.available()) { + Serial.printf("Unused stack: %d\n", uxTaskGetStackHighWaterMark(0)); const char *ptr; String line = d.readStringUntil('\n'); line.trim(); @@ -737,17 +797,21 @@ void Display::initFromFile() { colbg = (bg>>19) << 11 | ((bg>>10)&0x3F) << 5 | ((bg>>3)&0x1F); } } else if( (ptr=strchr(s, '=')) ) { // one line with some data... - int x,y,w,n; - char text[30]; - n=sscanf(s, "%d,%d,%d", &y, &x, &w); - sscanf(ptr+1, "%30[^\r\n]", text); + float x,y,w; + int n; + char text[61]; + n=sscanf(s, "%f,%f,%f", &y, &x, &w); + sscanf(ptr+1, "%60[^\r\n]", text); if(sonde.config.disptype==1) { x*=xscale; y*=yscale; w*=xscale; } newlayouts[idx].de[what].x = x; newlayouts[idx].de[what].y = y; newlayouts[idx].de[what].width = n>2 ? w : WIDTH_AUTO; parseDispElement(text, newlayouts[idx].de+what); - Serial.printf("entry at %d,%d width=%d font %d, color=%x,%x\n", x, y, newlayouts[idx].de[what].width, newlayouts[idx].de[what].fmt, + Serial.printf("entry at %d,%d width=%d font %d, color=%x,%x\n", (int)x, (int)y, newlayouts[idx].de[what].width, newlayouts[idx].de[what].fmt, newlayouts[idx].de[what].fg, newlayouts[idx].de[what].bg); + if(newlayouts[idx].de[what].func == disp.drawGPS) { + newlayouts[idx].usegps = GPSUSE_BASE|GPSUSE_DIST|GPSUSE_BEARING; // just all for now + } what++; newlayouts[idx].de[what].func = NULL; } else { @@ -759,9 +823,7 @@ void Display::initFromFile() { break; } } - layouts = newlayouts; - nLayouts = idx+1; - /// DONE by caller setLayout(0); + replaceLayouts(newlayouts, idx+1); } void Display::circ(uint16_t *bm, int16_t size, int16_t x0, int16_t y0, int16_t r, uint16_t fg, boolean fill, uint16_t bg) { @@ -835,7 +897,9 @@ void Display::drawAlt(DispEntry *de) { drawString(de," "); return; } - snprintf(buf, 16, sonde.si()->alt>=1000?" %5.0fm":" %3.1fm", sonde.si()->alt); + float alt = sonde.si()->alt; + //testing only.... alt += 30000-454; + snprintf(buf, 16, alt>=1000?" %5.0fm":" %3.1fm", alt); drawString(de,buf+strlen(buf)-6); } void Display::drawHS(DispEntry *de) { @@ -925,8 +989,9 @@ void Display::drawFreq(DispEntry *de) { void Display::drawAFC(DispEntry *de) { if(!sonde.config.showafc) return; rdis->setFont(de->fmt); - if(sonde.si()->afc==0) { strcpy(buf, " "); } - else { snprintf(buf, 15, " %+3.2fk", sonde.si()->afc*0.001); } + //if(sonde.si()->afc==0) { strcpy(buf, " "); } + //else + { snprintf(buf, 15, " %+3.2fk", sonde.si()->afc*0.001); } drawString(de, buf+strlen(buf)-8); } void Display::drawIP(DispEntry *de) { @@ -944,6 +1009,69 @@ void Display::drawTelemetry(DispEntry *de) { #define PI (3.1415926535897932384626433832795) #endif // defined by Arduino.h #define radians(x) ( (x)*180.0F/PI ) +#define FAKEGPS 0 + +extern int lastCourse; // from RX_FSK.ino +void Display::calcGPS() { + // base data +#if FAKEGPS + gpsValid = true; + gpsLat = 48.9; + gpsLon = 13.3; + gpsAlt = 33000; +static int tmpc=0; + tmpc = (tmpc+5)%360; + gpsCourse = tmpc; +#else + gpsValid = nmea.isValid(); + gpsLon = nmea.getLongitude()*0.000001; + gpsLat = nmea.getLatitude()*0.000001; + long alt; + nmea.getAltitude(alt); gpsAlt=(int)(alt/1000); + gpsCourse = (int)(nmea.getCourse()/1000); + gpsCourseOld = false; + if(gpsCourse==0) { + // either north or not new + if(lastCourse!=0) // use old value... + { + gpsCourseOld = true; + gpsCourse = lastCourse; + } + } +#endif + // distance + if( gpsValid && (sonde.si()->validPos&0x03)==0x03 && (layout->usegps&GPSUSE_DIST)) { + float lat1 = nmea.getLatitude()*0.000001; + float lat2 = sonde.si()->lat; + float x = radians(nmea.getLongitude()*0.000001-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; + } else { + gpsDist = -1; + } + // bearing + if( gpsValid && (sonde.si()->validPos&0x03)==0x03 && (layout->usegps&GPSUSE_BEARING)) { + float lat1 = radians(gpsLat); + float lat2 = radians(sonde.si()->lat); + float lon1 = radians(gpsLon); + 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; + if(gpsBear < 0) gpsBear += 360; + if(gpsBear >= 360) gpsBear -= 360; + } else { + gpsDir = -1; + gpsBear = -1; + } + + Serial.printf("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); +} void Display::drawGPS(DispEntry *de) { if(sonde.config.gps_rxd<0) return; @@ -952,40 +1080,28 @@ void Display::drawGPS(DispEntry *de) { case 'V': { // show if GPS location is valid - uint8_t *tile = nmea.isValid()?gps_tile:nogps_tile; + uint8_t *tile = disp.gpsValid?gps_tile:nogps_tile; rdis->drawTile(de->x, de->y, 1, tile); } break; case 'O': // GPS long - { - float lon = nmea.getLongitude()*0.000001; - Serial.print("lon: "); Serial.println(lon); - snprintf(buf, 16, "%2.5f", lon); + snprintf(buf, 16, "%2.5f", disp.gpsLon); drawString(de,buf); - } break; case 'A': // GPS lat - { - float lat = nmea.getLatitude()*0.000001; - Serial.print("lat: "); Serial.println(lat); - snprintf(buf, 16, "%2.5f", lat); + snprintf(buf, 16, "%2.5f", disp.gpsLat); drawString(de,buf); - } break; case 'H': // GPS alt - { - long alt = -1; - nmea.getAltitude(alt); - snprintf(buf, 16, "%4.0fm", alt*0.001); + snprintf(buf, 16, "%4dm", disp.gpsAlt); drawString(de,buf); - } break; case 'C': // GPS Course over ground - snprintf(buf, 4, "%3d", (int)(nmea.getCourse()/1000)); + snprintf(buf, 4, "%3d", disp.gpsCourse); drawString(de, buf); break; case 'D': @@ -995,23 +1111,18 @@ 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(!nmea.isValid()) { + } else if(!disp.gpsValid) { snprintf(buf, 16, "no gps "); if(de->extra && *de->extra=='5') buf[5]=0; } else { - float lat1 = nmea.getLatitude()*0.000001; - float lat2 = sonde.si()->lat; - float x = radians(nmea.getLongitude()*0.000001-sonde.si()->lon) * cos( radians((lat1+lat2)/2) ); - float y = radians(lat2-lat1); - float d = sqrt(x*x+y*y)*EARTH_RADIUS; if(de->extra && *de->extra=='5') { // 5-character version: ****m / ***km / **e6m - if(d>999999) snprintf(buf, 16, "%de6m ", (int)(d/1000000)); - if(d>9999) snprintf(buf, 16, "%dkm ", (int)(d/1000)); - else snprintf(buf, 16, "%dm ", (int)d); + if(disp.gpsDist>999999) snprintf(buf, 16, "%de6m ", (int)(disp.gpsDist/1000000)); + if(disp.gpsDist>9999) snprintf(buf, 16, "%dkm ", (int)(disp.gpsDist/1000)); + else snprintf(buf, 16, "%dm ", (int)disp.gpsDist); buf[5]=0; } else { // 6-character version: *****m / ****km) - if(d>99999) snprintf(buf, 16, "%dkm ", (int)(d/1000)); - else snprintf(buf, 16, "%dm ", (int)d); + if(disp.gpsDist>99999) snprintf(buf, 16, "%dkm ", (int)(disp.gpsDist/1000)); + else snprintf(buf, 16, "%dm ", (int)disp.gpsDist); buf[6]=0; } } @@ -1020,59 +1131,37 @@ void Display::drawGPS(DispEntry *de) { break; case 'I': // dIrection - if( (!nmea.isValid()) || ((sonde.si()->validPos&0x03)!=0x03 ) ) { + if( (!disp.gpsValid) || ((sonde.si()->validPos&0x03)!=0x03 ) ) { drawString(de, "---"); break; } - { - float lat1 = radians(nmea.getLatitude()*0.000001); - float lat2 = radians(sonde.si()->lat); - float lon1 = radians(nmea.getLongitude()*0.000001); - 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; - Serial.printf("direction is %.2f\n", dir); - snprintf(buf, 16, "%3d", (int)dir); + snprintf(buf, 16, "%3d", disp.gpsDir); buf[3]=0; drawString(de, buf); if(de->extra[1]==(char)176) rdis->drawTile(de->x+3, de->y, 1, deg_tile); - } break; case 'B': // relative bearing - if( (!nmea.isValid()) || ((sonde.si()->validPos&0x03)!=0x03 ) ) { + if( (!disp.gpsValid) || ((sonde.si()->validPos&0x03)!=0x03 ) ) { drawString(de, "---"); break; } - { - float lat1 = radians(nmea.getLatitude()*0.000001); - float lat2 = radians(sonde.si()->lat); - float lon1 = radians(nmea.getLongitude()*0.000001); - 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; - Serial.printf("direction is %.2f\n", dir); - float course = nmea.getCourse()*0.001; - float bearing = dir - course; - if(bearing<0) bearing += 360; - if(bearing>=360) bearing -= 360; - snprintf(buf, 16, "%3d", (int)bearing); + snprintf(buf, 16, "%3d", disp.gpsBear); buf[3]=0; drawString(de, buf); if(de->extra[1]==(char)176) rdis->drawTile(de->x+3, de->y, 1, deg_tile); - } break; case '0': // diagram { + static int alpha = 0; + alpha = (alpha+5)%360; struct CircleInfo *circinfo = (struct CircleInfo *)de->extra; - int size = 1 + 2*circinfo->radius + 2*circinfo->brad; + int border = circinfo->brad; + if(border<7) border=7; // space for "N" label + int size = 1 + 2*circinfo->radius + 2*border; uint16_t *bitmap = (uint16_t *)malloc(sizeof(uint16_t) * size * size); Serial.printf("Drawing circle with size %d at %d,%d\n",size,de->x, de->y); for(int i=0; iradius, de->fg, true, de->bg); - circ(bitmap, size, x0+circinfo->radius, y0, circinfo->brad, 0xff00, true, 0xff00); + // + 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; } + else { angA=disp.gpsDir; validA=sonde.si()->validPos?(rxgood?1:-1):0; } + if(circinfo->bul=='C') { angB=disp.gpsCourse; 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; + angA += angN; if(angA>=360) angA-=360; + angB += angN; if(angB>=360) angB-=360; + } + Serial.printf("GPS0: %c%c%c N=%d, A=%d, B=%d\n", circinfo->top, circinfo->arr, circinfo->bul, angN, angA, angB); + // "N" in direction angN + static_cast(rdis)->tft->drawGFXcharBM(x0 + circinfo->radius*sin(angN*PI/180)-6, y0 - circinfo->radius*cos(angN*PI/180)+7, 'N', 0xffff, bitmap, size); + + // small circle in direction angB + if(validB) { + circ(bitmap, size, x0+circinfo->radius*sin(angB*PI/180), y0-circinfo->radius*cos(angB*PI/180), circinfo->brad, + circinfo->bcol, true, validB==1?circinfo->bcol:0); + } rdis->drawBitmap(de->x, de->y, bitmap, size, size); + // triangle in direction angA + uint16_t xa,ya,xb,yb,xc,yc; + float xf=sin(angA*PI/180); + float yf=cos(angA*PI/180); + xa = de->x + x0 + xf*circinfo->radius; + ya = de->y + y0 - yf*circinfo->radius; + xb = de->x + x0 + yf*circinfo->awidth; + yb = de->y + y0 + xf*circinfo->awidth; + xc = de->x + x0 - yf*circinfo->awidth; + yc = de->y + y0 - xf*circinfo->awidth; + Serial.printf("%d: %d,%d\n", alpha, xa, ya); + if(validA==-1) + rdis->drawTriangle(xa,ya,xb,yb,xc,yc,circinfo->acol, false); + else if(validA==1) + rdis->drawTriangle(xa,ya,xb,yb,xc,yc,circinfo->acol, true); free(bitmap); } break; @@ -1091,6 +1219,49 @@ void Display::drawGPS(DispEntry *de) { } } +void Display::drawBatt(DispEntry *de) { + float val; + char buf[30]; + if(!axp192_found) return; + switch(de->extra[0]) { + case 'S': + if(!axp.isBatteryConnect()) { + if(axp.isVBUSPlug()) { strcpy(buf, "U"); } + else { strcpy(buf, "N"); } // no battary + } + else if (axp.isChargeing()) { strcpy(buf, "C"); } // charging + else { strcpy(buf, "B"); } // battery, but not charging + break; + case 'V': + val = axp.getBattVoltage(); + snprintf(buf, 30, "%.2f%s", val/1000, de->extra+1); + break; + case 'C': + val = axp.getBattChargeCurrent(); + snprintf(buf, 30, "%.2f%s", val, de->extra+1); + break; + case 'D': + val = axp.getBattDischargeCurrent(); + snprintf(buf, 30, "%.2f%s", val, de->extra+1); + break; + case 'U': + val = axp.getVbusVoltage(); + snprintf(buf, 30, "%.2f%s", val/1000, de->extra+1); + break; + case 'I': + val = axp.getVbusCurrent(); + snprintf(buf, 30, "%.2f%s", val, de->extra+1); + break; + case 'T': + val = axp.getTemp()-144.7; // WTF... library returns temperatur in K above -144.7°C!?? + snprintf(buf, 30, "%.2f%s", val, de->extra+1); + break; + default: + *buf=0; + } + drawString(de, buf); +} + void Display::drawText(DispEntry *de) { rdis->setFont(de->fmt); drawString(de, de->extra); @@ -1143,6 +1314,7 @@ void Display::updateDisplayIP() { } void Display::updateDisplay() { + calcGPS(); for(DispEntry *di=layout->de; di->func != NULL; di++) { di->func(di); } diff --git a/libraries/SondeLib/Display.h b/libraries/SondeLib/Display.h index 85352c8..5ab1f0f 100644 --- a/libraries/SondeLib/Display.h +++ b/libraries/SondeLib/Display.h @@ -20,15 +20,21 @@ struct DispEntry { const char *extra; }; +#define GPSUSE_BASE 1 +#define GPSUSE_DIST 2 +#define GPSUSE_BEARING 4 struct DispInfo { DispEntry *de; uint8_t *actions; int16_t *timeouts; - char *label; + const char *label; + uint8_t usegps; }; -struct CircleInfo { +struct CircleInfo { // 3,5=g0NCS,50,ff0000,000033,5,ffff00,4,ffffff char type; + char top,bul,arr; // what to point to with top, bullet, array + uint16_t fgcol, bgcol; uint8_t radius; uint8_t brad; uint16_t bcol; @@ -45,6 +51,7 @@ public: virtual void getDispSize(uint8_t *height, uint8_t *width, uint8_t *lineskip, uint8_t *colskip) = 0; virtual void drawString(uint8_t x, uint8_t y, const char *s, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0 ) = 0; virtual void drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr) = 0; + virtual void drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color, bool fill) = 0; virtual void drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h) = 0; virtual void welcome() = 0; virtual void drawIP(uint8_t x, uint8_t y, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0 ) = 0; @@ -66,6 +73,7 @@ public: void getDispSize(uint8_t *height, uint8_t *width, uint8_t *lineskip, uint8_t *colskip); void drawString(uint8_t x, uint8_t y, const char *s, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0); void drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr); + void drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color, bool fill); void drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h); void welcome(); void drawIP(uint8_t x, uint8_t y, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0); @@ -80,18 +88,18 @@ public: class ILI9225Display : public RawDisplay { private: - MY_ILI9225 *tft = NULL; // initialize later after reading config file uint8_t yofs=0; uint8_t findex=0; - public: + MY_ILI9225 *tft = NULL; // initialize later after reading config file void begin(); void clear(); void setFont(uint8_t fontindex); void getDispSize(uint8_t *height, uint8_t *width, uint8_t *lineskip, uint8_t *colskip); void drawString(uint8_t x, uint8_t y, const char *s, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0); void drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr); + void drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color, bool fill); void drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h); void welcome(); void drawIP(uint8_t x, uint8_t y, int16_t width=WIDTH_AUTO, uint16_t fg=0xffff, uint16_t bg=0); @@ -99,7 +107,7 @@ public: class Display { private: - void freeLayouts(); + void replaceLayouts(DispInfo *newlayout, int nnew); int allocDispInfo(int entries, DispInfo *d, char *label); void parseDispElement(char *text, DispEntry *de); int xscale=13, yscale=22; @@ -107,6 +115,13 @@ private: uint16_t colfg, colbg; 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 + boolean gpsCourseOld; public: void initFromFile(); @@ -136,6 +151,7 @@ public: static void drawTelemetry(DispEntry *de); static void drawGPS(DispEntry *de); static void drawText(DispEntry *de); + static void drawBatt(DispEntry *de); static void drawString(DispEntry *de, const char *str); void clearIP(); void setIP(const char *ip, bool AP); diff --git a/libraries/SondeLib/RS41.cpp b/libraries/SondeLib/RS41.cpp index 31af27a..5fc1735 100644 --- a/libraries/SondeLib/RS41.cpp +++ b/libraries/SondeLib/RS41.cpp @@ -381,16 +381,18 @@ int RS41::decode41(byte *data, int maxlen) if(corr<0) { corr = reedsolomon41(data, 560, 230); // try long frame } +#if 0 Serial.print("RS result:"); Serial.print(corr); Serial.println(); +#endif int p = 57; // 8 byte header, 48 byte RS while(pmaxlen) break; -#if 1 +#if 0 // DEBUG OUTPUT Serial.print("@"); Serial.print(p-2); diff --git a/libraries/SondeLib/Sonde.cpp b/libraries/SondeLib/Sonde.cpp index d4015f3..b6a5f0d 100644 --- a/libraries/SondeLib/Sonde.cpp +++ b/libraries/SondeLib/Sonde.cpp @@ -398,7 +398,7 @@ void Sonde::receive() { si->lastState = 0; } } - Serial.printf("debug: res was %d, now lastState is %d\n", res, si->lastState); + // Serial.printf("debug: res was %d, now lastState is %d\n", res, si->lastState); // we should handle timer events here, because after returning from receive, @@ -434,7 +434,7 @@ uint16_t Sonde::waitRXcomplete() { rxloop: while( rxtask.receiveResult==0xFFFF && millis()-t0 < 2000) { delay(50); } if( rxtask.receiveResult == RX_UPDATERSSI ) { - Serial.println("RSSI update"); + Serial.print("RSSI update: "); rxtask.receiveResult = 0xFFFF; disp.updateDisplayRSSI(); goto rxloop; @@ -517,6 +517,8 @@ uint8_t Sonde::updateState(uint8_t event) { if(config.display[i]==-1 || config.display[i+1]==-1) { //unknown index, or end of list => loop to start n = config.display[1]; + } else { + n = config.display[i+1]; } } if(n>=0 && nfirst); + GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); + uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap); + + uint16_t bo = pgm_read_word(&glyph->bitmapOffset); + uint8_t w = pgm_read_byte(&glyph->width), + h = pgm_read_byte(&glyph->height), + xa = pgm_read_byte(&glyph->xAdvance); + int8_t xo = pgm_read_byte(&glyph->xOffset), + yo = pgm_read_byte(&glyph->yOffset); + uint8_t xx, yy, bits = 0, bit = 0; + + for(yy=0; yy=bmwd) continue; + if(y+yo+yy<0) continue; // yo can be negative + for(xx=0; xx=bmwd) continue; + if(!(bit++ & 7)) { + bits = pgm_read_byte(&bitmap[bo++]); + } + if(bits & 0x80) { + bm[x+xo+xx + bmwd*(y+yo+yy)] = color; + } + bits <<= 1; + } + } + + return (uint16_t)xa; +} + void TFT22_ILI9225::getGFXCharExtent(uint8_t c, int16_t *gw, int16_t *gh, int16_t *xa) { uint8_t first = pgm_read_byte(&gfxFont->first), diff --git a/libraries/SondeLib/TFT22_ILI9225.h b/libraries/SondeLib/TFT22_ILI9225.h index ce5c3f0..9e049f7 100644 --- a/libraries/SondeLib/TFT22_ILI9225.h +++ b/libraries/SondeLib/TFT22_ILI9225.h @@ -389,6 +389,8 @@ class TFT22_ILI9225 { /// @return width of character in display pixels uint16_t drawGFXChar(int16_t x, int16_t y, unsigned char c, uint16_t color); + uint16_t drawGFXcharBM(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t *bm, int bmwd); + void getGFXCharExtent(uint8_t c, int16_t *gw, int16_t *gh, int16_t *xa); private: