G0 (circle diagram) and Vbatt for the display

This commit is contained in:
Hansi, dl9rdz 2019-10-21 20:51:21 +02:00
parent be64a7bf5f
commit 4e593b38e0
10 changed files with 402 additions and 111 deletions

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
#include <U8x8lib.h>
#include <U8g2lib.h>
#include <SPIFFS.h>
#include <axp20x.h>
#include <MicroNMEA.h>
#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<MAXSCREENS; i++) {
if(old[i].de) free(old[i].de);
}
@ -543,6 +566,16 @@ int Display::allocDispInfo(int entries, DispInfo *d, char *label)
return 0;
}
uint16_t encodeColor(uint32_t col) {
return (col>>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; i<size*size; i++) { bitmap[i] = 0; }
@ -1080,8 +1169,47 @@ void Display::drawGPS(DispEntry *de) {
int x0=size/2;
int y0=x0;
circ(bitmap, size, x0, y0, circinfo->radius, 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<ILI9225Display *>(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);
}

View File

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

View File

@ -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(p<maxlen) { /* why 555? */
uint8_t typ = data[p++];
uint32_t len = data[p++]+2UL;
if(p+len>maxlen) break;
#if 1
#if 0
// DEBUG OUTPUT
Serial.print("@");
Serial.print(p-2);

View File

@ -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 && n<ACT_MAXDISPLAY) {
@ -578,16 +580,11 @@ void Sonde::updateDisplayIP() {
disp.updateDisplayIP();
}
void Sonde::updateDisplayScanner() {
// TODO: WTF??? not used any more?
disp.setLayout(config.display[0]);
disp.updateDisplay();
disp.setLayout(config.display[1]);
}
void Sonde::updateDisplay()
{
int t = millis();
disp.updateDisplay();
Serial.printf("updateDisplay took %d ms\n", (int)(millis()-t));
}
void Sonde::clearDisplay() {

View File

@ -206,7 +206,6 @@ public:
void updateStat();
void updateDisplayIP();
void updateDisplay();
void updateDisplayScanner();
void clearDisplay();
void setIP(String ip, bool isAP);

View File

@ -1343,6 +1343,38 @@ uint16_t TFT22_ILI9225::drawGFXChar(int16_t x, int16_t y, unsigned char c, uint1
return (uint16_t)xa;
}
// Write a character to a bitmap
uint16_t TFT22_ILI9225::drawGFXcharBM(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t *bm, int bmwd) {
c -= (uint8_t)pgm_read_byte(&gfxFont->first);
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<h; yy++) {
if(y+yo+yy>=bmwd) continue;
if(y+yo+yy<0) continue; // yo can be negative
for(xx=0; xx<w; xx++) {
if(x+xo+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),

View File

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