diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index 0646a55..c092738 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -387,15 +387,23 @@ struct st_configitems config_list[] = { {"wifi", "Wifi mode (0/1/2/3)", 0, &sonde.config.wifi}, {"debug", "Debug mode (0/1)", 0, &sonde.config.debug}, {"maxsonde", "Maxsonde", 0, &sonde.config.maxsonde}, - {"display", "Display mode (1/2/3)", 0, &sonde.config.display}, + {"display", "Display screens (scan,default,...)", -6, sonde.config.display}, /* Spectrum display settings */ {"spectrum", "Show spectrum (-1=no, 0=forever, >0=seconds)", 0, &sonde.config.spectrum}, {"startfreq", "Startfreq (MHz)", 0, &sonde.config.startfreq}, {"channelbw", "Bandwidth (kHz)", 0, &sonde.config.channelbw}, {"marker", "Spectrum MHz marker", 0, &sonde.config.marker}, {"noisefloor", "Sepctrum noisefloor", 0, &sonde.config.noisefloor}, + /* decoder settings */ + {"", "Receiver configuration", -5, NULL}, {"showafc", "Show AFC value", 0, &sonde.config.showafc}, {"freqofs", "RX frequency offset (Hz)", 0, &sonde.config.freqofs}, + {"rs41.agcbw", "RS41 AGC bandwidth", 0, &sonde.config.rs41.agcbw}, + {"rs41.rxbw", "RS41 RX bandwidth", 0, &sonde.config.rs41.rxbw}, + {"rs92.rxbw", "RS92 RX (and AGC) bandwidth", 0, &sonde.config.rs92.rxbw}, + {"rs92.alt2d", "RS92 2D fix default altitude", 0, &sonde.config.rs92.alt2d}, + {"dfm.agcbw", "DFM6/9 AGC bandwidth", 0, &sonde.config.dfm.agcbw}, + {"dfm.rxbw", "DFM6/9 RX bandwidth", 0, &sonde.config.dfm.rxbw}, {"", "Data feed configuration", -5, NULL}, /* APRS settings */ {"call", "Call", 8, sonde.config.call}, @@ -415,14 +423,6 @@ struct st_configitems config_list[] = { {"tcp.port", "APRS TCP Port", 0, &sonde.config.tcpfeed.port}, {"tcp.idformat", "DFM ID Format", -2, &sonde.config.tcpfeed.idformat}, {"tcp.highrate", "Rate limit", 0, &sonde.config.tcpfeed.highrate}, - /* decoder settings */ - {"", "Receiver configuration", -5, NULL}, - {"rs41.agcbw", "RS41 AGC bandwidth", 0, &sonde.config.rs41.agcbw}, - {"rs41.rxbw", "RS41 RX bandwidth", 0, &sonde.config.rs41.rxbw}, - {"rs92.rxbw", "RS92 RX (and AGC) bandwidth", 0, &sonde.config.rs92.rxbw}, - {"rs92.alt2d", "RS92 2D fix default altitude", 0, &sonde.config.rs92.alt2d}, - {"dfm.agcbw", "DFM6/9 AGC bandwidth", 0, &sonde.config.dfm.agcbw}, - {"dfm.rxbw", "DFM6/9 RX bandwidth", 0, &sonde.config.dfm.rxbw}, /* Hardware dependeing settings */ {"", "Hardware configuration (requires reboot)", -5, NULL}, {"disptype", "Display type (0=OLED/SSD1306, 1=TFT/ILI9225, 2=OLED/SH1106)", 0, &sonde.config.disptype}, @@ -434,7 +434,7 @@ struct st_configitems config_list[] = { {"button_pin", "Button input port", -4, &sonde.config.button_pin}, {"button2_pin", "Button 2 input port", -4, &sonde.config.button2_pin}, {"touch_thresh", "Touch button threshold", 0, &sonde.config.touch_thresh}, - {"power_pout", "Power control port", 0, &sonde.config.power_pout}, + {"power_pout", "Power control port", 0, &sonde.config.power_pout}, {"led_pout", "LED output port", 0, &sonde.config.led_pout}, {"gps_rxd", "GPS RXD pin (-1 to disable)", 0, &sonde.config.gps_rxd}, {"gps_txd", "GPS TXD pin (not really needed)", 0, &sonde.config.gps_txd}, @@ -468,14 +468,37 @@ void addConfigHeading(char *ptr, const char *label) { strcat(ptr, label); strcat(ptr, "\n"); } +void addConfigInt8List(char *ptr, int idx, const char *label, int8_t *list) { + sprintf(ptr + strlen(ptr), "%s", label); + for (int i = 0; i < disp.nLayouts; i++) { + sprintf(ptr + strlen(ptr), "
%d=%s", i, disp.layouts[i].label); + } + sprintf(ptr + strlen(ptr), "\n"); +} const char *createConfigForm() { char *ptr = message; strcpy(ptr, "
"); for (int i = 0; i < N_CONFIG; i++) { switch (config_list[i].type) { - case -5: // Heading + case -5: // Heading addConfigHeading(ptr, config_list[i].label); + break; + case -6: // List of int8 values + addConfigInt8List(ptr, i, config_list[i].label, (int8_t *)config_list[i].data); + break; case -3: // in/offt addConfigOnOffEntry(ptr, i, config_list[i].label, (int *)config_list[i].data); break; @@ -879,18 +902,18 @@ char buffer[85]; MicroNMEA nmea(buffer, sizeof(buffer)); void unkHandler(const MicroNMEA& nmea) { - if(strcmp(nmea.getMessageID(), "VTG")==0) { + 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 + 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); } } void gpsTask(void *parameter) { nmea.setUnknownSentenceHandler(unkHandler); - + while (1) { while (Serial2.available()) { char c = Serial2.read(); @@ -902,7 +925,7 @@ void gpsTask(void *parameter) { long alt = -1; bool b = nmea.getAltitude(alt); bool valid = nmea.isValid(); - int course = nmea.getCourse()/1000; + int course = nmea.getCourse() / 1000; uint8_t hdop = nmea.getHDOP(); //Serial.printf("\nDecode: valid: %d N %ld E %ld alt %ld (%d) course:%d dop:%d", valid ? 1 : 0, lat, lon, alt, b, c, hdop); } @@ -1112,7 +1135,6 @@ int scanI2Cdevice(void) } extern int initlevels[40]; -extern DispInfo *layouts; bool pmu_irq = false; @@ -1197,9 +1219,9 @@ void setup() sleep(500); } } - if(sonde.config.power_pout>=0) { // for a heltec v2, pull GPIO21 low for display power - pinMode(sonde.config.power_pout&127, OUTPUT); - digitalWrite(sonde.config.power_pout&127, sonde.config.power_pout&128?1:0); + if (sonde.config.power_pout >= 0) { // for a heltec v2, pull GPIO21 low for display power + pinMode(sonde.config.power_pout & 127, OUTPUT); + digitalWrite(sonde.config.power_pout & 127, sonde.config.power_pout & 128 ? 1 : 0); } LORA_LED = sonde.config.led_pout; @@ -1228,10 +1250,10 @@ void setup() sonde.clearDisplay(); setupWifiList(); - Serial.printf("before disp.initFromFile... layouts is %p", layouts); + Serial.printf("before disp.initFromFile... layouts is %p", disp.layouts); disp.initFromFile(); - Serial.printf("disp.initFromFile... layouts is %p", layouts); + Serial.printf("disp.initFromFile... layouts is %p", disp.layouts); // == show initial values from config.txt ========================= // @@ -1453,6 +1475,10 @@ void loopDecoder() { Serial.println("updateDisplay done"); } +void setCurrentDisplay(int value) { + Serial.printf("setCurrentDisplay: setting index %d, entry %d\b", value, sonde.config.display[value]); + currentDisplay = sonde.config.display[value]; +} void loopSpectrum() { int marker = 0; @@ -1469,7 +1495,7 @@ void loopSpectrum() { enterMode(ST_WIFISCAN); return; case KP_DOUBLE: - currentDisplay = 0; + setCurrentDisplay(0); enterMode(ST_DECODER); return; default: break; @@ -1484,7 +1510,7 @@ void loopSpectrum() { itoa((sonde.config.startfreq + 6), buf, 10); disp.rdis->drawString(13, 1, buf); } - if (sonde.config.spectrum>0) { + if (sonde.config.spectrum > 0) { int remaining = sonde.config.spectrum - (millis() - specTimer) / 1000; itoa(remaining, buf, 10); Serial.printf("config.spectrum:%d specTimer:%ld millis:%ld remaining:%d\n", sonde.config.spectrum, specTimer, millis(), remaining); @@ -1494,7 +1520,7 @@ void loopSpectrum() { disp.rdis->drawString(0, 1 + marker, buf); disp.rdis->drawString(2, 1 + marker, "Sec."); if (remaining <= 0) { - currentDisplay = 0; + setCurrentDisplay(0); enterMode(ST_DECODER); } } @@ -1533,7 +1559,9 @@ void enableNetwork(bool enable) { SetupAsyncServer(); udp.begin(WiFi.localIP(), LOCALUDPPORT); MDNS.addService("http", "tcp", 80); - if(sonde.config.kisstnc.active) { tncserver.begin(); } + if (sonde.config.kisstnc.active) { + tncserver.begin(); + } connected = true; } else { MDNS.end(); @@ -1744,7 +1772,7 @@ void initialMode() { if (sonde.config.spectrum != -1) { // enable Spectrum in config.txt: spectrum=number_of_seconds startSpectrumDisplay(); } else { - currentDisplay = 0; + setCurrentDisplay(0); enterMode(ST_DECODER); } } @@ -1861,15 +1889,6 @@ void loopWifiScan() { } enableNetwork(true); initialMode(); -#if 0 - // done already in initialMode - if (sonde.config.spectrum != -1) { // enable Spectrum in config.txt: spectrum=number_of_seconds (0=forever) - enterMode(ST_SPECTRUM); - } else { - currentDisplay = 0; - enterMode(ST_DECODER); - } -#endif } diff --git a/RX_FSK/data/config.txt b/RX_FSK/data/config.txt index a6cd674..2ce548a 100644 --- a/RX_FSK/data/config.txt +++ b/RX_FSK/data/config.txt @@ -35,15 +35,17 @@ wifi=3 # TCP/IP KISS TNC in port 14590 for APRSdroid (0=disabled, 1=enabled) kisstnc.active = 1 -# display mode: 1=standard 2=fieldmode 3=field w/sondetype -display=1 +# display configuration. List of "displays" +# first entry: "Scanner" display +# second entry: default "Receiver" display +# additional entries: alternative receiver display, activated by button +display=0,1,2,3,4 #-------------------------------# # Spectrum display settings #-------------------------------# startfreq=400 channelbw=10 spectrum=10 -timer=1 noisefloor=-125 marker=1 #-------------------------------# diff --git a/RX_FSK/data/screens.txt b/RX_FSK/data/screens.txt index 4c32980..7936a76 100644 --- a/RX_FSK/data/screens.txt +++ b/RX_FSK/data/screens.txt @@ -90,7 +90,7 @@ # => Button press activates default receiver view, double press does nothing # Mid press activates Spectrum display, long press activates Wifi scan # - key2 has no function -@Scanner:5 +@Scanner timer=-1,0,0 key1action=D,#,F,W key2action=#,#,#,# @@ -113,7 +113,7 @@ timeaction=#,D,+ # - timer actions: #,#,0 # (norx timer: if no signal for >20 seconds: go back to scanner mode) # -@Legacy:11 +@Legacy timer=-1,-1,20000 key1action=+,0,F,W key2action=2,#,#,# @@ -133,7 +133,7 @@ timeaction=#,#,0 ############ # Configuratoon for "Field" display (display 2) # similar to @Legacy, but no norx timer, and Key2 goes to display 4 -@Field:7 +@Field timer=-1,-1,-1 key1action=+,0,F,W key2action=3,#,#,# @@ -149,7 +149,7 @@ timeaction=#,#,# ############ # Configuration for "Field2" display (display 3) # similar to @Field -@Field2:9 +@Field2 timer=-1,-1,-1 key1action=+,0,F,W key2action=4,#,#,# @@ -167,7 +167,7 @@ timeaction=#,#,# ############# # Configuration for "GPS" display # not yet the final version, just for testing -@GPSDIST:14 +@GPSDIST timer=-1,-1,-1 key1action=+,0,F,W key2action=1,#,#,# @@ -187,3 +187,45 @@ timeaction=#,#,# 7,2=xd= 7,4=gD 7,12=gI° + +############ +# Scan display for large 2" TFT dispaly +@ScannerTFT +timer=-1,0,0 +key1action=D,#,F,W +key2action=#,#,#,# +timeaction=#,D,+ +font=5,6 +0,0=XScan: +0,8=T +3,0=F MHz +5,0=S +7,5=n + +############ +@MainTFT +timer=-1,-1,20000 +key1action=+,0,F,W +key2action=2,#,#,# +timeaction=#,#,0 +color=FFD700 +0,0=Is +color=0000FF +0,9,-7=f +1,1,6=c +1,12,-4=t +color=00ff00 +2,0=L +4,0=O +color=FFA500 +2,9,-7=A +3,9,-7=vm/s +color=AA5522 +4,9,-7=hkkm/h +color=FFFFFF +6,2=r +7,0=xd= +7,2,6=gD +7,12=gI + + diff --git a/libraries/SondeLib/Display.cpp b/libraries/SondeLib/Display.cpp index 7c6ddb9..f2bc054 100644 --- a/libraries/SondeLib/Display.cpp +++ b/libraries/SondeLib/Display.cpp @@ -163,13 +163,12 @@ uint8_t gpsActions[] = { ACT_NONE, ACT_NONE, ACT_NONE}; DispInfo staticLayouts[5] = { - { searchLayout, searchActions, searchTimeouts }, - { legacyLayout, legacyActions, legacyTimeouts }, - { fieldLayout, fieldActions, fieldTimeouts }, - { field2Layout, field2Actions, fieldTimeouts }, - { gpsLayout, gpsActions, fieldTimeouts } }; + { searchLayout, searchActions, searchTimeouts, "StaticSearch" }, + { legacyLayout, legacyActions, legacyTimeouts, "StaticLegacy" }, + { fieldLayout, fieldActions, fieldTimeouts, "StaticField1" }, + { field2Layout, field2Actions, fieldTimeouts, "StaticFiel2" }, + { gpsLayout, gpsActions, fieldTimeouts, "StaticGPS" } }; -DispInfo *layouts = staticLayouts; /////////////// Wrapper code for various display @@ -413,7 +412,7 @@ void ILI9225Display::drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap void ILI9225Display::welcome() { tft->clear(); setFont(6); - drawString(0, 0*22, version_name, WIDTH_AUTO, 0xff77); + drawString(0, 0*22, version_name, WIDTH_AUTO, 0xff00); setFont(5); drawString(0, 1*22, "RS41,RS92,DFM6/9"); drawString(0, 3*22, version_id); @@ -503,10 +502,11 @@ void Display::init() { Display::Display() { + layouts = staticLayouts; setLayout(0); } -#define MAXSCREENS 10 +#define MAXSCREENS 20 #define DISP_ACTIONS_N 12 #define DISP_TIMEOUTS_N 3 @@ -522,7 +522,7 @@ void Display::freeLayouts() { free(old); } -int Display::allocDispInfo(int entries, DispInfo *d) +int Display::allocDispInfo(int entries, DispInfo *d, char *label) { int totalsize = (entries+1)*sizeof(DispEntry) + DISP_ACTIONS_N*sizeof(uint8_t) + DISP_TIMEOUTS_N * sizeof(int16_t); char *mem = (char *)malloc(totalsize); @@ -537,6 +537,8 @@ int Display::allocDispInfo(int entries, DispInfo *d) d->actions[0] = ACT_NONE; d->timeouts = (int16_t *)mem; + + d->label = label; Serial.printf("allocated %d bytes (%d entries) for %p (addr=%p)\n", totalsize, entries, d, d->de); return 0; } @@ -632,17 +634,35 @@ static uint8_t ACTION(char c) { return ACT_NONE; } +int Display::countEntries(File f) { + int pos = f.position(); + int n = 0; + while(1) { + String line = f.readStringUntil('\n'); + line.trim(); + const char *c=line.c_str(); + if(*c=='#') continue; + if(*c>='0'&&*c<='9') n++; + if(strchr(c,'=')) continue; + break; + } + f.seek(pos, SeekSet); + Serial.printf("Counted %d entries\n", n); + return n; +} + void Display::initFromFile() { File d = SPIFFS.open("/screens.txt", "r"); if(!d) return; freeLayouts(); - DispInfo *layouts = (DispInfo *)malloc(MAXSCREENS * sizeof(DispInfo)); - if(!layouts) { + DispInfo *newlayouts = (DispInfo *)malloc(MAXSCREENS * sizeof(DispInfo)); + if(!newlayouts) { + Serial.println("Init from file: FAILED, using static layouts"); layouts = staticLayouts; return; } - memset(layouts, 0, MAXSCREENS * sizeof(DispInfo)); + memset(newlayouts, 0, MAXSCREENS * sizeof(DispInfo)); // default color colfg = 0xffff; // white; only used for ILI9225 @@ -665,15 +685,11 @@ void Display::initFromFile() { Serial.printf("Illegal start of screen: %s\n", s); continue; } - char *num = strchr(s, ':'); - if(!num) { - Serial.println("Line missing size length indication"); - continue; - } - entrysize = atoi(num+1); + entrysize = countEntries(d); Serial.printf("Reading entry with %d elements\n", entrysize); idx++; - int res = allocDispInfo(entrysize, &layouts[idx]); + int res = allocDispInfo(entrysize, &newlayouts[idx], strdup(s+1)); + Serial.printf("allocDispInfo: idx %d: label is %p - %s\n",idx,newlayouts[idx].label, newlayouts[idx].label); if(res<0) { Serial.println("Error allocating memory for disp info"); continue; @@ -683,29 +699,29 @@ void Display::initFromFile() { break; default: // parse content... (additional data or line `what`) if(strncmp(s,"timer=",6)==0) { // timer values - sscanf(s+6, "%hd,%hd,%hd", layouts[idx].timeouts, layouts[idx].timeouts+1, layouts[idx].timeouts+2); - Serial.printf("timer values: %d, %d, %d\n", layouts[idx].timeouts[0], layouts[idx].timeouts[1], layouts[idx].timeouts[2]); + sscanf(s+6, "%hd,%hd,%hd", newlayouts[idx].timeouts, newlayouts[idx].timeouts+1, newlayouts[idx].timeouts+2); + Serial.printf("timer values: %d, %d, %d\n", newlayouts[idx].timeouts[0], newlayouts[idx].timeouts[1], newlayouts[idx].timeouts[2]); } else if(strncmp(s, "key1action=",11)==0) { // key 1 actions char c1,c2,c3,c4; sscanf(s+11, "%c,%c,%c,%c", &c1, &c2, &c3, &c4); - layouts[idx].actions[1] = ACTION(c1); - layouts[idx].actions[2] = ACTION(c2); - layouts[idx].actions[3] = ACTION(c3); - layouts[idx].actions[4] = ACTION(c4); + newlayouts[idx].actions[1] = ACTION(c1); + newlayouts[idx].actions[2] = ACTION(c2); + newlayouts[idx].actions[3] = ACTION(c3); + newlayouts[idx].actions[4] = ACTION(c4); } else if(strncmp(s, "key2action=",11)==0) { // key 2 actions char c1,c2,c3,c4; sscanf(s+11, "%c,%c,%c,%c", &c1, &c2, &c3, &c4); - layouts[idx].actions[5] = ACTION(c1); - layouts[idx].actions[6] = ACTION(c2); - layouts[idx].actions[7] = ACTION(c3); - layouts[idx].actions[8] = ACTION(c4); + newlayouts[idx].actions[5] = ACTION(c1); + newlayouts[idx].actions[6] = ACTION(c2); + newlayouts[idx].actions[7] = ACTION(c3); + newlayouts[idx].actions[8] = ACTION(c4); Serial.printf("parsing key2action: %c %c %c %c\n", c1, c2, c3, c4); } else if(strncmp(s, "timeaction=",11)==0) { // timer actions char c1,c2,c3; sscanf(s+11, "%c,%c,%c", &c1, &c2, &c3); - layouts[idx].actions[9] = ACTION(c1); - layouts[idx].actions[10] = ACTION(c2); - layouts[idx].actions[11] = ACTION(c3); + newlayouts[idx].actions[9] = ACTION(c1); + newlayouts[idx].actions[10] = ACTION(c2); + newlayouts[idx].actions[11] = ACTION(c3); } else if(strncmp(s, "fonts=",6)==0) { // change font sscanf(s+6, "%d,%d", &fontsma, &fontlar); } else if(strncmp(s, "scale=",6)==0) { // change line->pixel scaling for ILI9225 display @@ -724,24 +740,25 @@ void Display::initFromFile() { n=sscanf(s, "%d,%d,%d", &y, &x, &w); sscanf(ptr+1, "%30[^\r\n]", text); if(sonde.config.disptype==1) { x*=xscale; y*=yscale; w*=xscale; } - layouts[idx].de[what].x = x; - layouts[idx].de[what].y = y; - layouts[idx].de[what].width = n>2 ? w : WIDTH_AUTO; - parseDispElement(text, layouts[idx].de+what); - Serial.printf("entry at %d,%d width=%d font %d, color=%x,%x\n", x, y, layouts[idx].de[what].width, layouts[idx].de[what].fmt, - layouts[idx].de[what].fg, layouts[idx].de[what].bg); + 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, + newlayouts[idx].de[what].fg, newlayouts[idx].de[what].bg); what++; - layouts[idx].de[what].func = NULL; + newlayouts[idx].de[what].func = NULL; } else { for(int i=0; i<12; i++) { - Serial.printf("action %d: %d\n", i, (int)layouts[idx].actions[i]); + Serial.printf("action %d: %d\n", i, (int)newlayouts[idx].actions[i]); } what=-1; } break; } } - ::layouts = layouts; + layouts = newlayouts; + nLayouts = idx+1; setLayout(0); } @@ -782,6 +799,8 @@ void Display::circ(uint16_t *bm, int16_t size, int16_t x0, int16_t y0, int16_t r void Display::setLayout(int layoutIdx) { + Serial.printf("setLayout: %d (max is %d)\n", layoutIdx, nLayouts); + if(layoutIdx>=nLayouts) layoutIdx = 0; layout = &layouts[layoutIdx]; } diff --git a/libraries/SondeLib/Scanner.cpp b/libraries/SondeLib/Scanner.cpp index ec0b87e..9706372 100644 --- a/libraries/SondeLib/Scanner.cpp +++ b/libraries/SondeLib/Scanner.cpp @@ -62,13 +62,6 @@ void Scanner::plotResult() void Scanner::scan() { -#if 0 - // Test only - for(int i=0; i=0&&n<5) { + if(n>=0&&n
OptionValue