diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index 93f4535..ba190cc 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -2,8 +2,8 @@ #include #include #include -#include -#include +//#include +//#include #include #include #include @@ -19,12 +19,6 @@ #include "geteph.h" #include "rs92gps.h" -// UNCOMMENT one of the constructor lines below -U8X8_SSD1306_128X64_NONAME_SW_I2C *u8x8 = NULL; // initialize later after reading config file -//U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ OLED_SCL, /* data=*/ OLED_SDA, /* reset=*/ OLED_RST); // Unbuffered, basic graphics, software I2C -//U8G2_SSD1306_128X64_NONAME_1_SW_I2C Display(U8G2_R0, /* clock=*/ OLED_SCL, /* data=*/ OLED_SDA, /* reset=*/ OLED_RST); // Page buffer, SW I2C -//U8G2_SSD1306_128X64_NONAME_F_SW_I2C Display(U8G2_R0, /* clock=*/ OLED_SCL, /* data=*/ OLED_SDA, /* reset=*/ OLED_RST); // Full framebuffer, SW I2C - int LORA_LED = 9; // default POUT for LORA LED used as serial monitor int e; @@ -49,7 +43,6 @@ WiFiClient client; WiFiServer tncserver(14580); WiFiClient tncclient; - enum KeyPress { KP_NONE = 0, KP_SHORT, KP_DOUBLE, KP_MID, KP_LONG }; // "doublepress" is now also used to eliminate key glitch on TTGO T-Beam startup (SENSOR_VN/GPIO39) @@ -351,7 +344,10 @@ const char *createStatusForm() { strcpy(ptr, ""); for (int i = 0; i < sonde.nSonde; i++) { - addSondeStatus(ptr, (i + sonde.currentSonde) % sonde.nSonde); + int snum = (i + sonde.currentSonde) % sonde.nSonde; + if (sonde.sondeList[snum].active) { + addSondeStatus(ptr, snum); + } } strcat(ptr, ""); return message; @@ -427,9 +423,12 @@ struct st_configitems config_list[] = { {"dfm.rxbw", "DFM6/9 RX bandwidth", 0, &sonde.config.dfm.rxbw}, {"---", "---", -1, NULL}, /* Hardware dependeing settings */ - {"oled_sda", "OLED SDA (needs reboot)", 0, &sonde.config.oled_sda}, - {"oled_scl", "OLED SCL (needs reboot)", 0, &sonde.config.oled_scl}, - {"oled_rst", "OLED RST (needs reboot)", 0, &sonde.config.oled_rst}, + {"disptype", "Display type (0=OLED, 1=TFT/ILI9225)", 0, &sonde.config.disptype}, + {"oled_sda", "OLED/TFT SDA (needs reboot)", 0, &sonde.config.oled_sda}, + {"oled_scl", "OLED SCL/TFT CLK (needs reboot)", 0, &sonde.config.oled_scl}, + {"oled_rst", "OLED/TFT RST (needs reboot)", 0, &sonde.config.oled_rst}, + {"tft_rs", "TFT RS (needs reboot)", 0, &sonde.config.tft_rs}, + {"tft_cs", "TFT CS (needs reboot)", 0, &sonde.config.tft_cs}, {"button_pin", "Button input port (needs reboot)", -4, &sonde.config.button_pin}, {"button2_pin", "Button 2 input port (needs reboot)", -4, &sonde.config.button2_pin}, {"touch_thresh", "Touch button threshold (needs reboot)", 0, &sonde.config.touch_thresh}, @@ -1090,18 +1089,16 @@ void setup() } initTouch(); - u8x8 = new U8X8_SSD1306_128X64_NONAME_SW_I2C(/* clock=*/ sonde.config.oled_scl, /* data=*/ sonde.config.oled_sda, /* reset=*/ sonde.config.oled_rst); // Unbuffered, basic graphics, software I2C - u8x8->begin(); + disp.init(); delay(100); + disp.rdis->clear(); - u8x8->clear(); - - u8x8->setFont(u8x8_font_7x14_1x2_r); - u8x8->drawString(8 - strlen(version_name) / 2, 1, version_name); - u8x8->drawString(8 - strlen(version_id) / 2, 3, version_id); - u8x8->setFont(u8x8_font_chroma48medium8_r); - u8x8->drawString(0, 5, "by Hansi, DL9RDZ"); - u8x8->drawString(1, 6, "Mods by DL2MF"); + disp.rdis->setFont(FONT_LARGE); + disp.rdis->drawString(8 - strlen(version_name) / 2, 1, version_name); + disp.rdis->drawString(8 - strlen(version_id) / 2, 3, version_id); + disp.rdis->setFont(FONT_SMALL); + disp.rdis->drawString(0, 5, "by Hansi, DL9RDZ"); + disp.rdis->drawString(1, 6, "Mods by DL2MF"); delay(3000); sonde.clearDisplay(); @@ -1115,38 +1112,38 @@ void setup() // == show initial values from config.txt ========================= // if (sonde.config.debug == 1) { - u8x8->setFont(u8x8_font_chroma48medium8_r); - u8x8->drawString(0, 0, "Config:"); + disp.rdis->setFont(FONT_SMALL); + disp.rdis->drawString(0, 0, "Config:"); delay(500); itoa(sonde.config.oled_sda, buf, 10); - u8x8->drawString(0, 1, " SDA:"); - u8x8->drawString(6, 1, buf); + disp.rdis->drawString(0, 1, " SDA:"); + disp.rdis->drawString(6, 1, buf); delay(500); itoa(sonde.config.oled_scl, buf, 10); - u8x8->drawString(0, 2, " SCL:"); - u8x8->drawString(6, 2, buf); + disp.rdis->drawString(0, 2, " SCL:"); + disp.rdis->drawString(6, 2, buf); delay(500); itoa(sonde.config.oled_rst, buf, 10); - u8x8->drawString(0, 3, " RST:"); - u8x8->drawString(6, 3, buf); + disp.rdis->drawString(0, 3, " RST:"); + disp.rdis->drawString(6, 3, buf); delay(1000); itoa(sonde.config.led_pout, buf, 10); - u8x8->drawString(0, 4, " LED:"); - u8x8->drawString(6, 4, buf); + disp.rdis->drawString(0, 4, " LED:"); + disp.rdis->drawString(6, 4, buf); delay(500); itoa(sonde.config.spectrum, buf, 10); - u8x8->drawString(0, 5, " SPEC:"); - u8x8->drawString(6, 5, buf); + disp.rdis->drawString(0, 5, " SPEC:"); + disp.rdis->drawString(6, 5, buf); delay(500); itoa(sonde.config.maxsonde, buf, 10); - u8x8->drawString(0, 6, " MAX:"); - u8x8->drawString(6, 6, buf); + disp.rdis->drawString(0, 6, " MAX:"); + disp.rdis->drawString(6, 6, buf); delay(5000); sonde.clearDisplay(); @@ -1229,7 +1226,7 @@ void enterMode(int mode) { if (mainState == ST_SPECTRUM) { Serial.println("Entering ST_SPECTRUM mode"); sonde.clearDisplay(); - u8x8->setFont(u8x8_font_chroma48medium8_r); + disp.rdis->setFont(FONT_SMALL); specTimer = millis(); //scanner.init(); } else if (mainState == ST_WIFISCAN) { @@ -1288,14 +1285,14 @@ void loopDecoder() { if (!tncclient.connected()) { Serial.println("TNC client not connected"); tncclient = tncserver.available(); - if(tncclient.connected()) { + if (tncclient.connected()) { Serial.println("new TCP KISS connection"); } } if (tncclient.available()) { Serial.print("TCP KISS socket: recevied "); while (tncclient.available()) { - Serial.print(tncclient.read()); // Check if we receive anything from Bluetooth + Serial.print(tncclient.read()); // Check if we receive anything from from APRSdroid } Serial.println(""); } @@ -1316,12 +1313,12 @@ void loopDecoder() { udp.write((const uint8_t *)raw, rawlen); udp.endPacket(); } - if(tncclient.connected()) { - Serial.println("Sending position via TCP"); - char raw[201]; - int rawlen = aprsstr_mon2kiss(str, raw, APRS_MAXLEN); - Serial.print("sending: "); Serial.println(raw); - tncclient.write(raw, rawlen); + if (tncclient.connected()) { + Serial.println("Sending position via TCP"); + char raw[201]; + int rawlen = aprsstr_mon2kiss(str, raw, APRS_MAXLEN); + Serial.print("sending: "); Serial.println(raw); + tncclient.write(raw, rawlen); } } } @@ -1354,10 +1351,10 @@ void loopSpectrum() { scanner.plotResult(); if (sonde.config.marker != 0) { itoa((sonde.config.startfreq), buf, 10); - u8x8->drawString(0, 1, buf); - u8x8->drawString(7, 1, "MHz"); + disp.rdis->drawString(0, 1, buf); + disp.rdis->drawString(7, 1, "MHz"); itoa((sonde.config.startfreq + 6), buf, 10); - u8x8->drawString(13, 1, buf); + disp.rdis->drawString(13, 1, buf); } if (sonde.config.timer) { int remaining = sonde.config.spectrum - (millis() - specTimer) / 1000; @@ -1366,8 +1363,8 @@ void loopSpectrum() { if (sonde.config.marker != 0) { marker = 1; } - u8x8->drawString(0, 1 + marker, buf); - u8x8->drawString(2, 1 + marker, "Sec."); + disp.rdis->drawString(0, 1 + marker, buf); + disp.rdis->drawString(2, 1 + marker, "Sec."); if (remaining <= 0) { currentDisplay = 0; enterMode(ST_DECODER); @@ -1377,8 +1374,8 @@ void loopSpectrum() { void startSpectrumDisplay() { sonde.clearDisplay(); - u8x8->setFont(u8x8_font_chroma48medium8_r); - u8x8->drawString(0, 0, "Spectrum Scan..."); + disp.rdis->setFont(FONT_SMALL); + disp.rdis->drawString(0, 0, "Spectrum Scan..."); delay(500); enterMode(ST_SPECTRUM); } @@ -1649,8 +1646,8 @@ void loopWifiScan() { return; } // wifi==3 => original mode with non-async wifi setup - u8x8->setFont(u8x8_font_chroma48medium8_r); - u8x8->drawString(0, 0, "WiFi Scan..."); + disp.rdis->setFont(FONT_SMALL); + disp.rdis->drawString(0, 0, "WiFi Scan..."); int line = 0; int cnt = 0; @@ -1663,7 +1660,7 @@ void loopWifiScan() { Serial.print("Network name: "); String ssid = WiFi.SSID(i); Serial.println(ssid); - u8x8->drawString(0, 1 + line, ssid.c_str()); + disp.rdis->drawString(0, 1 + line, ssid.c_str()); line = (line + 1) % 5; Serial.print("Signal strength: "); Serial.println(WiFi.RSSI(i)); @@ -1683,8 +1680,8 @@ void loopWifiScan() { Serial.print("Connecting to: "); Serial.print(fetchWifiSSID(index)); Serial.print(" with password "); Serial.println(fetchWifiPw(index)); - u8x8->drawString(0, 6, "Conn:"); - u8x8->drawString(6, 6, fetchWifiSSID(index)); + disp.rdis->drawString(0, 6, "Conn:"); + disp.rdis->drawString(6, 6, fetchWifiSSID(index)); WiFi.begin(fetchWifiSSID(index), fetchWifiPw(index)); while (WiFi.status() != WL_CONNECTED && cnt < MAXWIFIDELAY) { delay(500); @@ -1698,7 +1695,7 @@ void loopWifiScan() { Serial.print(" with password "); Serial.println(fetchWifiPw(index)); delay(500); } - u8x8->drawString(15, 7, _scan[cnt & 1]); + disp.rdis->drawString(15, 7, _scan[cnt & 1]); cnt++; } } @@ -1709,8 +1706,8 @@ void loopWifiScan() { IPAddress myIP = WiFi.softAPIP(); Serial.print("AP IP address: "); Serial.println(myIP); - u8x8->drawString(0, 6, "AP: "); - u8x8->drawString(6, 6, networks[0].id.c_str()); + disp.rdis->drawString(0, 6, "AP: "); + disp.rdis->drawString(6, 6, networks[0].id.c_str()); delay(3000); } else { Serial.println(""); @@ -1756,17 +1753,17 @@ void execOTA() { int contentLength = 0; bool isValidContentType = false; sonde.clearDisplay(); - u8x8->setFont(u8x8_font_chroma48medium8_r); - u8x8->drawString(0, 0, "C:"); + disp.rdis->setFont(FONT_SMALL); + disp.rdis->drawString(0, 0, "C:"); String dispHost = updateHost.substring(0, 14); - u8x8->drawString(2, 0, dispHost.c_str()); + disp.rdis->drawString(2, 0, dispHost.c_str()); Serial.println("Connecting to: " + updateHost); // Connect to Update host if (client.connect(updateHost.c_str(), updatePort)) { // Connection succeeded, fecthing the bin Serial.println("Fetching bin: " + String(*updateBin)); - u8x8->drawString(0, 1, "Fetching update"); + disp.rdis->drawString(0, 1, "Fetching update"); // Get the contents of the bin file client.print(String("GET ") + *updateBin + " HTTP/1.1\r\n" + @@ -1859,22 +1856,22 @@ void execOTA() { // Check what is the contentLength and if content type is `application/octet-stream` Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType)); - u8x8->drawString(0, 2, "Len: "); + disp.rdis->drawString(0, 2, "Len: "); String cls = String(contentLength); - u8x8->drawString(5, 2, cls.c_str()); + disp.rdis->drawString(5, 2, cls.c_str()); // check contentLength and content type if (contentLength && isValidContentType) { // Check if there is enough to OTA Update bool canBegin = Update.begin(contentLength); - u8x8->drawString(0, 4, "Starting update"); + disp.rdis->drawString(0, 4, "Starting update"); // If yes, begin if (canBegin) { Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!"); // No activity would appear on the Serial monitor // So be patient. This may take 2 - 5mins to complete - u8x8->drawString(0, 5, "Please wait!"); + disp.rdis->drawString(0, 5, "Please wait!"); size_t written = Update.writeStream(client); if (written == contentLength) { @@ -1889,7 +1886,7 @@ void execOTA() { Serial.println("OTA done!"); if (Update.isFinished()) { Serial.println("Update successfully completed. Rebooting."); - u8x8->drawString(0, 7, "Rebooting...."); + disp.rdis->drawString(0, 7, "Rebooting...."); delay(1000); ESP.restart(); } else { diff --git a/RX_FSK/data/config.txt b/RX_FSK/data/config.txt index 2ac9a4f..a6cd674 100644 --- a/RX_FSK/data/config.txt +++ b/RX_FSK/data/config.txt @@ -12,10 +12,17 @@ led_pout=9 # OLED Setup is depending on hardware of LoRa board # TTGO v1: SDA=4 SCL=15, RST=16 # TTGO v2: SDA=21 SCL=22, RST=16 +# T-BEAM, OLED: SDA=21, SCL=22, RST=16 +# T-BEAM, ILI9225: SDA=4, CLK=21, RS=2, RST=22, CS=0 # No specification in config file: try autodetection (gpio4 pin level at startup) +# +# disptype: 0=OLED, 1=ILI9225 +#disptype=0 #oled_sda=21 #oled_scl=22 -oled_rst=16 +#oled_rst=16 +#tft_rs=2 +#tft_cs=0 #gps_rxd=-1 gps_txd=-1 #-------------------------------# diff --git a/RX_FSK/version.h b/RX_FSK/version.h index a9dd625..216c637 100644 --- a/RX_FSK/version.h +++ b/RX_FSK/version.h @@ -1,2 +1,2 @@ const char *version_name = "RDZ_TTGO_SONDE"; -const char *version_id = "devel20190911"; +const char *version_id = "devel20190929"; diff --git a/libraries/SondeLib/Display.cpp b/libraries/SondeLib/Display.cpp index f502bd9..f652883 100644 --- a/libraries/SondeLib/Display.cpp +++ b/libraries/SondeLib/Display.cpp @@ -6,10 +6,13 @@ #include "Display.h" #include "Sonde.h" + +#include <../fonts/FreeSans9pt7b.h> +#include <../fonts/FreeSans12pt7b.h> + extern Sonde sonde; extern MicroNMEA nmea; -extern U8X8_SSD1306_128X64_NONAME_SW_I2C *u8x8; const char *sondeTypeStr[5] = { "DFM6", "DFM9", "RS41", "RS92" }; @@ -59,7 +62,6 @@ static uint8_t nogps_tile[8]={0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x00}; static uint8_t deg_tile[8]={0x00, 0x06,0x09, 0x09, 0x06, 0x00, 0x00, 0x00}; -#define SETFONT(large) u8x8->setFont((large)?u8x8_font_7x14_1x2_r:u8x8_font_chroma48medium8_r); /* Description of display layouts. * for each display, the content is described by a DispEntry structure @@ -162,8 +164,98 @@ DispInfo staticLayouts[5] = { DispInfo *layouts = staticLayouts; +/////////////// Wrapper code for various display + +void U8x8Display::begin() { + u8x8 = new U8X8_SSD1306_128X64_NONAME_SW_I2C(/* clock=*/ sonde.config.oled_scl, /* data=*/ sonde.config.oled_sda, /* reset=*/ sonde.config.oled_rst); // Unbuffered, basic graphics, software I2C + u8x8->begin(); + +} + +void U8x8Display::clear() { + u8x8->clear(); +} + +// For u8x8 oled display: 0=small font, 1=large font 7x14 +void U8x8Display::setFont(int large) { + u8x8->setFont((large)?u8x8_font_7x14_1x2_r:u8x8_font_chroma48medium8_r); +} + +void U8x8Display::drawString(uint8_t x, uint8_t y, const char *s) { + u8x8->drawString(x, y, s); +} + +void U8x8Display::drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr) { + u8x8->drawTile(x, y, cnt, tile_ptr); +} + + +#define TFT_LED 0 // 0 if wired to +5V directly +#define TFT_BRIGHTNESS 100 // Initial brightness of TFT backlight (optional) + +void ILI9225Display::begin() { + tft = new TFT_22_ILI9225(sonde.config.oled_rst, sonde.config.tft_rs, sonde.config.tft_cs, + sonde.config.oled_sda, sonde.config.oled_scl, TFT_LED, TFT_BRIGHTNESS); + tft->begin(); + tft->setOrientation(1); +} + +void ILI9225Display::clear() { + tft->clear(); +} + +// for now, 0=small=FreeSans9pt7b, 1=large=FreeSans18pt7b +void ILI9225Display::setFont(int large) { + tft->setGFXFont(large ? &FreeSans12pt7b : &FreeSans9pt7b); + //tft->setFont(large?Terminal12x16: Terminal6x8); + yofs = 0; +} + +void ILI9225Display::drawString(uint8_t x, uint8_t y, const char *s) { + int16_t w,h; + tft->getGFXTextExtent(s, x*14, y*14, &w, &h); + tft->fillRectangle(x*14, y*14, x*14+w, y*14+h, COLOR_BLACK); + tft->drawGFXText(x*14, y*14+h, s, COLOR_WHITE); + //tft->drawText(x*12, y*12, s, COLOR_WHITE); +} + +void ILI9225Display::drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr) { + int i,j; + for(int i=0; idrawPixel(8*x+i, 8*y+j, (v&0x01) ? COLOR_GREEN:COLOR_BLUE); + v >>= 1; + } + } + //tft->drawBitmap(x*8, y*8, tile_ptr, cnt*8, 8, COLOR_RED, COLOR_BLUE); + //???u8x8->drawTile(x, y, cnt, tile_ptr); +} + + + +/////////////// + + char Display::buf[17]; +RawDisplay *Display::rdis = NULL; + +//TODO: maybe merge with initFromFile later? +void Display::init() { + if(sonde.config.disptype==1) { + rdis = new ILI9225Display(); + } else { + rdis = new U8x8Display(); + } + Serial.println("Display created"); + rdis->begin(); + delay(100); + Serial.println("Display initialized"); + rdis->clear(); +} + + Display::Display() { setLayout(0); } @@ -372,85 +464,85 @@ void Display::setLayout(int layoutIdx) { } void Display::drawLat(DispEntry *de) { - SETFONT(de->fmt); + rdis->setFont(de->fmt); if(!sonde.si()->validPos) { - u8x8->drawString(de->x,de->y," "); + rdis->drawString(de->x,de->y," "); return; } snprintf(buf, 16, "%2.5f", sonde.si()->lat); - u8x8->drawString(de->x,de->y,buf); + rdis->drawString(de->x,de->y,buf); } void Display::drawLon(DispEntry *de) { - SETFONT(de->fmt); + rdis->setFont(de->fmt); if(!sonde.si()->validPos) { - u8x8->drawString(de->x,de->y," "); + rdis->drawString(de->x,de->y," "); return; } snprintf(buf, 16, "%2.5f", sonde.si()->lon); - u8x8->drawString(de->x,de->y,buf); + rdis->drawString(de->x,de->y,buf); } void Display::drawAlt(DispEntry *de) { - SETFONT(de->fmt); + rdis->setFont(de->fmt); if(!sonde.si()->validPos) { - u8x8->drawString(de->x,de->y," "); + rdis->drawString(de->x,de->y," "); return; } snprintf(buf, 16, sonde.si()->alt>=1000?" %5.0fm":" %3.1fm", sonde.si()->alt); - u8x8->drawString(de->x,de->y,buf+strlen(buf)-6); + rdis->drawString(de->x,de->y,buf+strlen(buf)-6); } void Display::drawHS(DispEntry *de) { - SETFONT(de->fmt); + rdis->setFont(de->fmt); if(!sonde.si()->validPos) { - u8x8->drawString(de->x,de->y," "); + rdis->drawString(de->x,de->y," "); return; } snprintf(buf, 16, sonde.si()->hs>99?" %3.0f":" %2.1f", sonde.si()->hs); - u8x8->drawString(de->x,de->y,buf+strlen(buf)-4); - u8x8->drawTile(de->x+4,de->y,2,kmh_tiles); + rdis->drawString(de->x,de->y,buf+strlen(buf)-4); + rdis->drawTile(de->x+4,de->y,2,kmh_tiles); } void Display::drawVS(DispEntry *de) { - SETFONT(de->fmt); + rdis->setFont(de->fmt); if(!sonde.si()->validPos) { - u8x8->drawString(de->x,de->y," "); + rdis->drawString(de->x,de->y," "); return; } snprintf(buf, 16, " %+2.1f", sonde.si()->vs); - u8x8->drawString(de->x, de->y, buf+strlen(buf)-5); - u8x8->drawTile(de->x+5,de->y,2,ms_tiles); + rdis->drawString(de->x, de->y, buf+strlen(buf)-5); + rdis->drawTile(de->x+5,de->y,2,ms_tiles); } void Display::drawID(DispEntry *de) { - SETFONT((de->fmt&0x01)); + rdis->setFont(de->fmt); if(!sonde.si()->validID) { - u8x8->drawString(de->x, de->y, "nnnnnnnn "); + rdis->drawString(de->x, de->y, "nnnnnnnn "); return; } // TODO: handle DFM6 IDs if(!de->extra || de->extra[0]=='s') { // real serial number, as printed on sonde - u8x8->drawString(de->x, de->y, sonde.si()->id); + rdis->drawString(de->x, de->y, sonde.si()->id); } else if (de->extra[0]=='a') { // autorx sonde number ("DF9" and last 6 digits of real serial number strcpy(buf, sonde.si()->id); memcpy(buf, "DF9", 3); - u8x8->drawString(de->x, de->y, buf); + rdis->drawString(de->x, de->y, buf); } else { // dxlAPRS sonde number (DF6 (why??) and 5 last digits of serial number as hex number uint32_t id = atoi(sonde.si()->id); id = id&0xfffff; snprintf(buf, 16, "DF6%05X", id); - u8x8->drawString(de->x, de->y, buf); + rdis->drawString(de->x, de->y, buf); } } void Display::drawRSSI(DispEntry *de) { - SETFONT(de->fmt); + rdis->setFont(de->fmt); snprintf(buf, 16, "-%d ", sonde.si()->rssi/2); int len=strlen(buf)-3; Serial.printf("drawRSSI: %d %d %d (%d)[%d]\n", de->y, de->x, sonde.si()->rssi/2, sonde.currentSonde, len); buf[5]=0; - u8x8->drawString(de->x,de->y,buf); - u8x8->drawTile(de->x+len, de->y, 1, (sonde.si()->rssi&1)?halfdb_tile1:empty_tile1); - u8x8->drawTile(de->x+len, de->y+1, 1, (sonde.si()->rssi&1)?halfdb_tile2:empty_tile2); + rdis->drawString(de->x,de->y,buf); + rdis->drawTile(de->x+len, de->y, 1, (sonde.si()->rssi&1)?halfdb_tile1:empty_tile1); + rdis->drawTile(de->x+len, de->y+1, 1, (sonde.si()->rssi&1)?halfdb_tile2:empty_tile2); } void Display::drawQS(DispEntry *de) { uint8_t *stat = sonde.si()->rxStat; @@ -458,32 +550,32 @@ void Display::drawQS(DispEntry *de) { uint8_t tile[8]; *(uint32_t *)(&tile[0]) = *(uint32_t *)(&(stattiles[stat[i]])); *(uint32_t *)(&tile[4]) = *(uint32_t *)(&(stattiles[stat[i+1]])); - u8x8->drawTile(de->x+i/2, de->y, 1, tile); + rdis->drawTile(de->x+i/2, de->y, 1, tile); } } void Display::drawType(DispEntry *de) { - SETFONT(de->fmt); - u8x8->drawString(de->x, de->y, sondeTypeStr[sonde.si()->type]); + rdis->setFont(de->fmt); + rdis->drawString(de->x, de->y, sondeTypeStr[sonde.si()->type]); } void Display::drawFreq(DispEntry *de) { - SETFONT(de->fmt); + rdis->setFont(de->fmt); snprintf(buf, 16, "%3.3f%s", sonde.si()->freq, de->extra?de->extra:""); - u8x8->drawString(de->x, de->y, buf); + rdis->drawString(de->x, de->y, buf); } void Display::drawAFC(DispEntry *de) { if(!sonde.config.showafc) return; - SETFONT(de->fmt); + rdis->setFont(de->fmt); if(sonde.si()->afc==0) { strcpy(buf, " "); } else { snprintf(buf, 15, " %+3.2fk", sonde.si()->afc*0.001); } - u8x8->drawString(de->x, de->y, buf+strlen(buf)-8); + rdis->drawString(de->x, de->y, buf+strlen(buf)-8); } void Display::drawIP(DispEntry *de) { - u8x8->drawTile(de->x, de->y, 11, myIP_tiles); + rdis->drawTile(de->x, de->y, 11, myIP_tiles); } void Display::drawSite(DispEntry *de) { - SETFONT(de->fmt); - u8x8->drawString(de->x, de->y, sonde.si()->launchsite); + rdis->setFont(de->fmt); + rdis->drawString(de->x, de->y, sonde.si()->launchsite); } void Display::drawTelemetry(DispEntry *de) { } @@ -496,13 +588,13 @@ void Display::drawTelemetry(DispEntry *de) { void Display::drawGPS(DispEntry *de) { if(sonde.config.gps_rxd<0) return; - SETFONT(de->fmt); + rdis->setFont(de->fmt); switch(de->extra[0]) { case 'V': { // show if GPS location is valid uint8_t *tile = nmea.isValid()?gps_tile:nogps_tile; - u8x8->drawTile(de->x, de->y, 1, tile); + rdis->drawTile(de->x, de->y, 1, tile); } break; case 'O': @@ -511,7 +603,7 @@ void Display::drawGPS(DispEntry *de) { float lon = nmea.getLongitude()*0.000001; Serial.print("lon: "); Serial.println(lon); snprintf(buf, 16, "%2.5f", lon); - u8x8->drawString(de->x,de->y,buf); + rdis->drawString(de->x,de->y,buf); } break; case 'A': @@ -520,7 +612,7 @@ void Display::drawGPS(DispEntry *de) { float lat = nmea.getLatitude()*0.000001; Serial.print("lat: "); Serial.println(lat); snprintf(buf, 16, "%2.5f", lat); - u8x8->drawString(de->x,de->y,buf); + rdis->drawString(de->x,de->y,buf); } break; case 'H': @@ -529,7 +621,7 @@ void Display::drawGPS(DispEntry *de) { long alt = -1; nmea.getAltitude(alt); snprintf(buf, 16, "%5fm", alt*0.00001); - u8x8->drawString(de->x,de->y,buf); + rdis->drawString(de->x,de->y,buf); } break; case 'D': @@ -559,13 +651,13 @@ void Display::drawGPS(DispEntry *de) { buf[6]=0; } } - u8x8->drawString(de->x, de->y, buf); + rdis->drawString(de->x, de->y, buf); } break; case 'I': // dIrection if( (!nmea.isValid()) || ((sonde.si()->validPos&0x03)!=0x03 ) ) { - u8x8->drawString(de->x, de->y, "---"); + rdis->drawString(de->x, de->y, "---"); break; } { @@ -580,9 +672,9 @@ void Display::drawGPS(DispEntry *de) { Serial.printf("direction is %.2f\n", dir); snprintf(buf, 16, "%3d", (int)dir); buf[3]=0; - u8x8->drawString(de->x, de->y, buf); + rdis->drawString(de->x, de->y, buf); if(de->extra[1]==(char)176) - u8x8->drawTile(de->x+3, de->y, 1, deg_tile); + rdis->drawTile(de->x+3, de->y, 1, deg_tile); } break; case 'E': @@ -591,8 +683,8 @@ void Display::drawGPS(DispEntry *de) { } } void Display::drawText(DispEntry *de) { - SETFONT(de->fmt); - u8x8->drawString(de->x, de->y, de->extra); + rdis->setFont(de->fmt); + rdis->drawString(de->x, de->y, de->extra); } diff --git a/libraries/SondeLib/Display.h b/libraries/SondeLib/Display.h index 2aff2b1..3c69e68 100644 --- a/libraries/SondeLib/Display.h +++ b/libraries/SondeLib/Display.h @@ -5,6 +5,10 @@ #define FONT_LARGE 1 #define FONT_SMALL 0 +#include +#include +#include + struct DispEntry { int8_t y; @@ -20,6 +24,40 @@ struct DispInfo { int16_t *timeouts; }; +// Now starting towards supporting different Display types / libraries +class RawDisplay { +public: + virtual void begin() = 0; + virtual void clear() = 0; + virtual void setFont(int nr) = 0; + virtual void drawString(uint8_t x, uint8_t y, const char *s) = 0; + virtual void drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr) = 0; +}; + +class U8x8Display : public RawDisplay { +private: + U8X8_SSD1306_128X64_NONAME_SW_I2C *u8x8 = NULL; // initialize later after reading config file + +public: + void begin(); + void clear(); + void setFont(int nr); + void drawString(uint8_t x, uint8_t y, const char *s); + void drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr); +}; + +class ILI9225Display : public RawDisplay { +private: + TFT_22_ILI9225 *tft = NULL; // initialize later after reading config file + uint8_t yofs=0; + +public: + void begin(); + void clear(); + void setFont(int nr); + void drawString(uint8_t x, uint8_t y, const char *s); + void drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr); +}; class Display { private: @@ -32,8 +70,10 @@ public: void setLayout(DispInfo *layout); DispInfo *layout; + static RawDisplay *rdis; Display(); + void init(); static char buf[17]; static void drawLat(DispEntry *de); static void drawLon(DispEntry *de); diff --git a/libraries/SondeLib/Scanner.cpp b/libraries/SondeLib/Scanner.cpp index 4239910..ec0b87e 100644 --- a/libraries/SondeLib/Scanner.cpp +++ b/libraries/SondeLib/Scanner.cpp @@ -3,8 +3,7 @@ #include #include "Sonde.h" - -extern U8X8_SSD1306_128X64_NONAME_SW_I2C *u8x8; +#include "Display.h" #define CHANBW 10 #define PIXSAMPL (50/CHANBW) @@ -56,7 +55,7 @@ void Scanner::plotResult() // don't overwrite MHz marker text if(i<3*8 || (i>=7*8&&i<10*8) || i>=13*8) continue; } - u8x8->drawTile(i/8, y, 1, row+8*y); + disp.rdis->drawTile(i/8, y, 1, row+8*y); } } } diff --git a/libraries/SondeLib/Sonde.cpp b/libraries/SondeLib/Sonde.cpp index d981299..cbd2280 100644 --- a/libraries/SondeLib/Sonde.cpp +++ b/libraries/SondeLib/Sonde.cpp @@ -8,7 +8,6 @@ #include "SX1278FSK.h" #include "Display.h" -extern U8X8_SSD1306_128X64_NONAME_SW_I2C *u8x8; extern SX1278FSK sx1278; RXTask rxtask = { -1, -1, -1, 0xFFFF, 0 }; @@ -51,6 +50,8 @@ Sonde::Sonde() { // Seems like on startup, GPIO4 is 1 on v1 boards, 0 on v2.1 boards? config.gps_rxd = -1; config.gps_txd = -1; + config.oled_rst = 16; + config.disptype = 0; if(initlevels[16]==0) { config.oled_sda = 4; config.oled_scl = 15; @@ -63,13 +64,21 @@ Sonde::Sonde() { config.button_pin = 39; config.button2_pin = T4 + 128; // T4 == GPIO13 config.gps_rxd = 12; + // Check if we possibly have a large display + if(initlevels[21]==0) { + config.disptype = 1; + config.oled_sda = 4; + config.oled_scl = 21; + config.oled_rst = 22; + config.tft_rs = 2; + config.tft_cs = 0; + } } else { config.button_pin = 2 + 128; // GPIO2 / T2 config.button2_pin = 14 + 128; // GPIO14 / T6 } } // - config.oled_rst = 16; config.noisefloor = -125; strcpy(config.call,"NOCALL"); strcpy(config.passcode, "---"); @@ -496,7 +505,7 @@ void Sonde::updateDisplay() } void Sonde::clearDisplay() { - u8x8->clearDisplay(); + disp.rdis->clear(); } Sonde sonde = Sonde(); diff --git a/libraries/SondeLib/Sonde.h b/libraries/SondeLib/Sonde.h index 36c11cd..a0ad31a 100644 --- a/libraries/SondeLib/Sonde.h +++ b/libraries/SondeLib/Sonde.h @@ -85,9 +85,12 @@ typedef struct st_rdzconfig { int button2_pin; // PIN port number menu button (+128 for touch mode) int touch_thresh; // Threshold value (0..100) for touch input button int led_pout; // POUT port number of LED (used as serial monitor) - int oled_sda; // OLED data pin - int oled_scl; // OLED clock pin - int oled_rst; // OLED reset pin + int disptype; // 0=OLED; 1=ILI9225 + int oled_sda; // OLED/TFT data pin + int oled_scl; // OLED/TFT clock pin + int oled_rst; // OLED/TFT reset pin + int tft_rs; // TFT RS pin + int tft_cs; // TFT CS pin int gps_rxd; // GPS module RXD pin. We expect 9600 baud NMEA data. int gps_txd; // GPS module TXD pin int debug; // show port and config options after reboot diff --git a/libraries/SondeLib/autodetect-infos b/libraries/SondeLib/autodetect-infos index f3067ef..cb11547 100644 --- a/libraries/SondeLib/autodetect-infos +++ b/libraries/SondeLib/autodetect-infos @@ -17,6 +17,10 @@ TTGO T-Beam 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:1 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:4 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-Beam with extern 2" ILI9225 Display +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:1 13:0 14:1 15:1 16:1 17:0 18:0 19:0 20:0 21:0 22:0 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:4 13:0 14:4 15:4 16:4 17:0 18:0 19:0 20:0 21:0 22:0 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) +1 Current autodetect strategy: RST always set to 16 @@ -30,13 +34,17 @@ GPIO16=0 (GPio22,23 would also work): otherwise ==LORA32 v2.1 or T-Beam== - SDA,SCL set to (21,22) GPIO17=0: == T-BEAM = GPS RX set to 12 Button 1 set to GPIO39 Button 2 set to Touch GPIO13 (141) + GPIO21=0: + large display connected (use ILI9225 contig: SDA4 CLK21 RS2 RST22 CS0) + else: + small display connected, set SDA,SCL to (21,22) otherweise: + SDA,SCL set to (21,22) GPS disabled Button 1 set to Touch GPIO2 (130) Button 2 set to Touch GPIO14 (142) diff --git a/libraries/SondeLib/geteph.cpp b/libraries/SondeLib/geteph.cpp index 944d499..ba78522 100644 --- a/libraries/SondeLib/geteph.cpp +++ b/libraries/SondeLib/geteph.cpp @@ -5,9 +5,9 @@ #include #include #include -#include +#include "Display.h" + -extern U8X8_SSD1306_128X64_NONAME_SW_I2C *u8x8; extern WiFiClient client; static const char *ftpserver = "www.ngs.noaa.gov"; @@ -72,9 +72,9 @@ void geteph() { Serial.printf("now: %s, existing: %s => updating\n", nowstr, tsstr); } status.close(); - u8x8->clear(); - u8x8->setFont(u8x8_font_chroma48medium8_r); - u8x8->drawString(0, 0, "FTP ngs.noaa.gov"); + disp.rdis->clear(); + disp.rdis->setFont(FONT_SMALL); + disp.rdis->drawString(0, 0, "FTP ngs.noaa.gov"); // fetch rinex from server File fh = SPIFFS.open("/brdc.gz","w"); if(!fh) { @@ -84,7 +84,7 @@ void geteph() { char buf[252]; snprintf(buf, 128, "/cors/rinex/%04d/%03d/brdc%03d0.%02dn.gz", year, day, day, year-2000); Serial.println("running geteph\n"); - u8x8->drawString(0, 1, buf+21); + disp.rdis->drawString(0, 1, buf+21); if(!client.connect(ftpserver, 21)) { Serial.println("FTP connection to www.ngs.noaa.gov failed"); @@ -145,9 +145,9 @@ void geteph() { fh.close(); snprintf(buf, 16, "Fetched %d B ",len); buf[16]=0; - u8x8->drawString(0,2,buf); + disp.rdis->drawString(0,2,buf); - u8x8->drawString(0,4,"Decompressing..."); + disp.rdis->drawString(0,4,"Decompressing..."); // decompression tinfl_decompressor *decomp = (tinfl_decompressor *)malloc(sizeof(tinfl_decompressor)); tinfl_init(decomp); @@ -215,7 +215,7 @@ void geteph() { status.close(); snprintf(buf, 16, "Done: %d B ",total); buf[16]=0; - u8x8->drawString(0,5,buf); + disp.rdis->drawString(0,5,buf); delay(1000); free(obuf);