kopia lustrzana https://github.com/dl9rdz/rdz_ttgo_sonde
Merge branch 'dl9rdz:devel' into devel
commit
c55b97c809
|
@ -61,6 +61,8 @@ commit_website_files() {
|
|||
git add ${BRANCH}/update.ino.bin
|
||||
echo "${TRAVIS_COMMIT_MESSAGE}" >> ${BRANCH}/${VERSION}-changelog.txt
|
||||
git add ${BRANCH}/${VERSION}-changelog.txt
|
||||
echo "<html><body><p>${VERSION}</p></body></html>" > ${BRANCH}/update-info.html
|
||||
git add ${BRANCH}/update-info.html
|
||||
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER"
|
||||
}
|
||||
upload_files() {
|
||||
|
|
|
@ -59,7 +59,19 @@ WiFiClient client;
|
|||
#define SONDEHUB_MOBILE_STATION_UPDATE_TIME (30*1000) // 30 sec
|
||||
WiFiClient shclient; // Sondehub v2
|
||||
unsigned long time_last_update = 0;
|
||||
/* SH_LOC_OFF: never send position information to SondeHub
|
||||
SH_LOC_FIXED: send fixed position (if specified in config) or GPS position (if there is a GPS fix) as fixed station position (no chase mode) to sondehub
|
||||
SH_LOC_CHASE: always activate chase mode and send GPS position (if available)
|
||||
SH_LOC_AUTO: if there is no valid GPS position, or GPS position < MIN_LOC_AUTO_DIST away from known fixed position: use FIXED mode
|
||||
otherwise, i.e. if there is a valid GPS position and (either no fixed position in config, or GPS position is far away from fixed position), use CHASE mode.
|
||||
*/
|
||||
enum { SH_LOC_OFF, SH_LOC_FIXED, SH_LOC_CHASE, SH_LOC_AUTO };
|
||||
/* auto mode is chase if valid GPS position and (no fixed location entered OR valid GPS position and distance in lat/lon deg to fixed location > threshold) */
|
||||
#define MIN_LOC_AUTO_DIST 200 /* meter */
|
||||
#define SH_LOC_AUTO_IS_CHASE ( gpsPos.valid && ( (isnan(sonde.config.sondehub.lat) || isnan(sonde.config.sondehub.lon) ) || \
|
||||
calcLatLonDist( gpsPos.lat, gpsPos.lon, sonde.config.sondehub.lat, sonde.config.sondehub.lon ) > MIN_LOC_AUTO_DIST ) )
|
||||
#endif
|
||||
extern float calcLatLonDist(float lat1, float lon1, float lat2, float lon2);
|
||||
|
||||
// KISS over TCP for communicating with APRSdroid
|
||||
WiFiServer tncserver(14580);
|
||||
|
@ -99,6 +111,8 @@ static unsigned long specTimer;
|
|||
void enterMode(int mode);
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
|
||||
char buffer[85];
|
||||
MicroNMEA nmea(buffer, sizeof(buffer));
|
||||
|
||||
// Read line from file, independent of line termination (LF or CR LF)
|
||||
String readLine(Stream &stream) {
|
||||
|
@ -186,7 +200,6 @@ void setupChannelList() {
|
|||
while (file.available()) {
|
||||
String line = readLine(file); //file.readStringUntil('\n');
|
||||
String sitename;
|
||||
if (!file.available()) break;
|
||||
if (line[0] == '#') continue;
|
||||
char *space = strchr(line.c_str(), ' ');
|
||||
if (!space) continue;
|
||||
|
@ -417,14 +430,14 @@ const char *createSondeHubMap() {
|
|||
HTMLBODY(ptr, "map.html");
|
||||
if (!sonde.config.sondehub.active) {
|
||||
strcat(ptr, "<div>NOTE: SondeHub uploading is not enabled, detected sonde will not be visable on map</div>");
|
||||
if ((*s->ser == 0) && (sonde.config.sondehub.lat[0] != '\0')) {
|
||||
sprintf(ptr + strlen(ptr), "<iframe src=\"https://sondehub.org/#!mc=%s,%s&mz=8\" style=\"border:1px solid #00A3D3;border-radius:20px;height:95vh\"></iframe>", sonde.config.sondehub.lat, sonde.config.sondehub.lon);
|
||||
if ((*s->ser == 0) && ( !isnan(sonde.config.sondehub.lat))) {
|
||||
sprintf(ptr + strlen(ptr), "<iframe src=\"https://sondehub.org/#!mc=%f,%f&mz=8\" style=\"border:1px solid #00A3D3;border-radius:20px;height:95vh\"></iframe>", sonde.config.sondehub.lat, sonde.config.sondehub.lon);
|
||||
} else {
|
||||
sprintf(ptr + strlen(ptr), "<iframe src=\"https://sondehub.org/%s\" style=\"border:1px solid #00A3D3;border-radius:20px;height:95vh\"></iframe>", s-> ser);
|
||||
}
|
||||
} else {
|
||||
if ((*s->ser == 0) && (sonde.config.sondehub.lat[0] != '\0')) {
|
||||
sprintf(ptr, "<iframe src=\"https://sondehub.org/#!mc=%s,%s&mz=8\" style=\"border:1px solid #00A3D3;border-radius:20px;height:98vh;width:100%%\"></iframe>", sonde.config.sondehub.lat, sonde.config.sondehub.lon);
|
||||
if ((*s->ser == 0) && (!isnan(sonde.config.sondehub.lat))) {
|
||||
sprintf(ptr, "<iframe src=\"https://sondehub.org/#!mc=%f,%f&mz=8\" style=\"border:1px solid #00A3D3;border-radius:20px;height:98vh;width:100%%\"></iframe>", sonde.config.sondehub.lat, sonde.config.sondehub.lon);
|
||||
} else {
|
||||
sprintf(ptr, "<iframe src=\"https://sondehub.org/%s\" style=\"border:1px solid #00A3D3;border-radius:20px;height:98vh;width:100%%\"></iframe>", s-> ser);
|
||||
}
|
||||
|
@ -516,6 +529,39 @@ const char *createStatusForm() {
|
|||
return message;
|
||||
}
|
||||
|
||||
const char *createLiveJson() {
|
||||
char *ptr = message;
|
||||
strcpy(ptr, "{");
|
||||
|
||||
SondeInfo *s = &sonde.sondeList[sonde.currentSonde];
|
||||
if (s->validID) {
|
||||
sprintf(ptr + strlen(ptr), "\"sonde\": {\"id\": \"%s\", \"freq\": %3.3f, \"type\": \"%s\", \"lat\": %.6f, \"lon\": %.6f, \"alt\": %.0f, \"speed\": %.1f, \"dir\": %.0f, \"climb\": %.1f }", s->id, s->freq, sondeTypeStr[s->type], s->lat, s->lon, s->alt, s->hs, s->dir, s->vs);
|
||||
} else {
|
||||
sprintf(ptr + strlen(ptr), "\"sonde\": {\"launchsite\": \"%s\",\"freq\": %3.3f, \"type\": \"%s\" }", s->launchsite, s->freq, sondeTypeStr[s->type]);
|
||||
}
|
||||
|
||||
if (sonde.config.gps_rxd < 0) {
|
||||
// gps disabled
|
||||
} else {
|
||||
long sat = nmea.getNumSatellites();
|
||||
long speed = nmea.getSpeed();
|
||||
long dir = nmea.getCourse();
|
||||
long lat = nmea.getLatitude();
|
||||
long lon = nmea.getLongitude();
|
||||
long alt = -1;
|
||||
/*bool b = */nmea.getAltitude(alt);
|
||||
bool valid = nmea.isValid();
|
||||
uint8_t hdop = nmea.getHDOP();
|
||||
if (valid) {
|
||||
strcat(ptr, ",");
|
||||
sprintf(ptr + strlen(ptr), "\"gps\": {\"lat\": %ld, \"lon\": %ld, \"alt\": %ld, \"sat\": %ld, \"speed\": %ld, \"dir\": %ld, \"hdop\": %d }", lat, lon, alt, sat, speed, dir, hdop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
strcat(ptr, "}");
|
||||
return message;
|
||||
}
|
||||
///////////////////// Config form
|
||||
|
||||
|
||||
|
@ -542,10 +588,10 @@ struct st_configitems {
|
|||
struct st_configitems config_list[] = {
|
||||
/* General config settings */
|
||||
{"", "Software configuration", -5, NULL},
|
||||
{"wifi", "Wifi mode (0/1/2/3)", 0, &sonde.config.wifi},
|
||||
{"wifi", "Wifi mode (0-Off/1-Client/2-Access Point/3-Debug)", 0, &sonde.config.wifi},
|
||||
{"debug", "Debug mode (0/1)", 0, &sonde.config.debug},
|
||||
{"maxsonde", "Maxsonde", 0, &sonde.config.maxsonde},
|
||||
{"screenfile", "Screen config (0=old, 1=OLED, 2=TFT, 3=TFT[port])", 0, &sonde.config.screenfile},
|
||||
{"maxsonde", "Maxsonde (max # QRG entries)", 0, &sonde.config.maxsonde},
|
||||
{"screenfile", "Screen config (0=automatic; 1-5=predefined; other=custom)", 0, &sonde.config.screenfile},
|
||||
{"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},
|
||||
|
@ -555,7 +601,6 @@ struct st_configitems config_list[] = {
|
|||
{"noisefloor", "Spectrum 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},
|
||||
|
@ -601,7 +646,7 @@ struct st_configitems config_list[] = {
|
|||
|
||||
/* 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},
|
||||
{"disptype", "Display type (0=OLED/SSD1306, 1=ILI9225, 2=OLED/SH1106, 3=ILI9341, 4=ILI9342)", 0, &sonde.config.disptype},
|
||||
{"norx_timeout", "No-RX-Timeout in seconds (-1=disabled)", 0, &sonde.config.norx_timeout},
|
||||
{"oled_sda", "OLED SDA/TFT SDA", 0, &sonde.config.oled_sda},
|
||||
{"oled_scl", "OLED SCL/TFT CLK", 0, &sonde.config.oled_scl},
|
||||
|
@ -609,7 +654,7 @@ struct st_configitems config_list[] = {
|
|||
{"tft_rs", "TFT RS", 0, &sonde.config.tft_rs},
|
||||
{"tft_cs", "TFT CS", 0, &sonde.config.tft_cs},
|
||||
{"tft_orient", "TFT orientation (0/1/2/3), OLED flip: 3", 0, &sonde.config.tft_orient},
|
||||
{"tft_modeflip", "TFT modeflip (usually 0)", 0, &sonde.config.tft_modeflip},
|
||||
{"tft_spifreq", "TFT SPI speed", 0, &sonde.config.tft_spifreq},
|
||||
{"button_pin", "Button input port", -4, &sonde.config.button_pin},
|
||||
{"button2_pin", "Button 2 input port", -4, &sonde.config.button2_pin},
|
||||
{"button2_axp", "Use AXP192 PWR as Button 2", 0, &sonde.config.button2_axp},
|
||||
|
@ -618,20 +663,26 @@ struct st_configitems config_list[] = {
|
|||
{"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},
|
||||
#if 1
|
||||
{"sx1278_ss", "SX1278 SS", 0, &sonde.config.sx1278_ss},
|
||||
{"sx1278_miso", "SX1278 MISO", 0, &sonde.config.sx1278_miso},
|
||||
{"sx1278_mosi", "SX1278 MOSI", 0, &sonde.config.sx1278_mosi},
|
||||
{"sx1278_sck", "SX1278 SCK", 0, &sonde.config.sx1278_sck},
|
||||
#endif
|
||||
{"mdnsname", "mDNS name", 14, &sonde.config.mdnsname},
|
||||
|
||||
#if FEATURE_SONDEHUB
|
||||
/* Sondehub v2 settings */
|
||||
{"", "Sondehub v2 settings", -5, NULL},
|
||||
{"sondehub.active", "Sondehub reporting active", 0, &sonde.config.sondehub.active},
|
||||
{"sondehub.chase", "Sondehub chase location active", 0, &sonde.config.sondehub.chase},
|
||||
{"sondehub.host", "Sondehub host", 63, &sonde.config.sondehub.host},
|
||||
/* SondeHub settings */
|
||||
{"", "SondeHub settings", -5, NULL},
|
||||
{"sondehub.active", "SondeHub reporting (0=disabled, 1=active)", 0, &sonde.config.sondehub.active},
|
||||
{"sondehub.chase", "SondeHub location reporting (0=off, 1=fixed, 2=chase/GPS, 3=auto)", 0, &sonde.config.sondehub.chase},
|
||||
{"sondehub.host", "SondeHub host (DO NOT CHANGE)", 63, &sonde.config.sondehub.host},
|
||||
{"sondehub.callsign", "Callsign", 63, &sonde.config.sondehub.callsign},
|
||||
{"sondehub.lat", "Latitude", 19, &sonde.config.sondehub.lat},
|
||||
{"sondehub.lon", "Longitude", 19, &sonde.config.sondehub.lon},
|
||||
{"sondehub.alt", "Altitude", 19, &sonde.config.sondehub.alt},
|
||||
{"sondehub.antenna", "Antenna", 63, &sonde.config.sondehub.antenna},
|
||||
{"sondehub.email", "Sondehub email", 63, &sonde.config.sondehub.email},
|
||||
{"sondehub.lat", "Latitude (optional, required to show station on SondeHub Tracker)", -7, &sonde.config.sondehub.lat},
|
||||
{"sondehub.lon", "Longitude (optional, required to show station on SondeHub Tracker)", -7, &sonde.config.sondehub.lon},
|
||||
{"sondehub.alt", "Altitude (optional, visible on SondeHub tracker)", 19, &sonde.config.sondehub.alt},
|
||||
{"sondehub.antenna", "Antenna (optional, visisble on SondeHub tracker)", 63, &sonde.config.sondehub.antenna},
|
||||
{"sondehub.email", "SondeHub email (optional, only used to contact in case of upload errors)", 63, &sonde.config.sondehub.email},
|
||||
#endif
|
||||
};
|
||||
const static int N_CONFIG = (sizeof(config_list) / sizeof(struct st_configitems));
|
||||
|
@ -644,6 +695,10 @@ void addConfigNumEntry(char *ptr, int idx, const char *label, int *value) {
|
|||
sprintf(ptr + strlen(ptr), "<tr><td>%s</td><td><input name=\"CFG%d\" type=\"text\" value=\"%d\"/></td></tr>\n",
|
||||
label, idx, *value);
|
||||
}
|
||||
void addConfigDblEntry(char *ptr, int idx, const char *label, double *value) {
|
||||
sprintf(ptr + strlen(ptr), "<tr><td>%s</td><td><input name=\"CFG%d\" type=\"text\" value=\"%f\"/></td></tr>\n",
|
||||
label, idx, *value);
|
||||
}
|
||||
void addConfigButtonEntry(char *ptr, int idx, const char *label, int *value) {
|
||||
int v = *value, ck = 0;
|
||||
if (v == 255) v = -1;
|
||||
|
@ -671,7 +726,7 @@ void addConfigHeading(char *ptr, const char *label) {
|
|||
strcat(ptr, "</th></tr>\n");
|
||||
}
|
||||
void addConfigInt8List(char *ptr, int idx, const char *label, int8_t *list) {
|
||||
sprintf(ptr + strlen(ptr), "<tr><td>%s", label);
|
||||
sprintf(ptr + strlen(ptr), "<tr><td>%s using /screens%d.txt", label, Display::getScreenIndex(sonde.config.screenfile));
|
||||
for (int i = 0; i < disp.nLayouts; i++) {
|
||||
sprintf(ptr + strlen(ptr), "<br>%d=%s", i, disp.layouts[i].label);
|
||||
}
|
||||
|
@ -718,6 +773,9 @@ const char *createConfigForm() {
|
|||
case -4:
|
||||
addConfigButtonEntry(ptr, i, config_list[i].label, (int *)config_list[i].data);
|
||||
break;
|
||||
case -7: /* double for lat/lon */
|
||||
addConfigDblEntry(ptr, i, config_list[i].label, (double *)config_list[i].data);
|
||||
break;
|
||||
default:
|
||||
addConfigStringEntry(ptr, i, config_list[i].label, config_list[i].type, (char *)config_list[i].data);
|
||||
break;
|
||||
|
@ -1010,7 +1068,11 @@ const char *createUpdateForm(boolean run) {
|
|||
if (run) {
|
||||
strcat(ptr, "<p>Doing update, wait until reboot</p>");
|
||||
} else {
|
||||
sprintf(ptr + strlen(ptr), "<p>Currently installed: %s-%c%d</p>\n", version_id, SPIFFS_MAJOR + 'A' - 1, SPIFFS_MINOR);
|
||||
strcat(ptr, "<p>Available master:: <iframe src=\"http://rdzsonde.mooo.com/master/update-info.html\" style=\"height:40px;width:400px\"></iframe><br>"
|
||||
"Available devel: <iframe src=\"http://rdzsonde.mooo.com/devel/update-info.html\" style=\"height:40px;width:400px\"></iframe></p>");
|
||||
strcat(ptr, "<input type=\"submit\" name=\"master\" value=\"Master-Update\"></input><br><input type=\"submit\" name=\"devel\" value=\"Devel-Update\">");
|
||||
strcat(ptr, "<br><p>Note: If suffix is the same, update should work fully. If the number is different, update contains changes in the file system. A full re-flash is required to get all new features, but the update should not break anything. If the letter is different, a full re-flash is mandatory, update will not work</p>");
|
||||
}
|
||||
strcat(ptr, "</form></body></html>");
|
||||
Serial.printf("Update form: size=%d bytes\n", strlen(message));
|
||||
|
@ -1173,6 +1235,15 @@ void SetupAsyncServer() {
|
|||
server.on("/status.html", HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||
request->send(200, "text/html", createStatusForm());
|
||||
});
|
||||
server.on("/live.json", HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||
request->send(200, "text/json", createLiveJson());
|
||||
});
|
||||
server.on("/livemap.html", HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||
request->send(SPIFFS, "/livemap.html", String(), false, processor);
|
||||
});
|
||||
server.on("/livemap.js", HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||
request->send(SPIFFS, "/livemap.js", String(), false, processor);
|
||||
});
|
||||
server.on("/update.html", HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||
request->send(200, "text/html", createUpdateForm(0));
|
||||
});
|
||||
|
@ -1218,7 +1289,7 @@ void SetupAsyncServer() {
|
|||
server.on("/edit.html", HTTP_POST, [](AsyncWebServerRequest * request) {
|
||||
const char *ret = handleEditPost(request);
|
||||
if (ret == NULL)
|
||||
request->send(200, "text/html", "<html><head>ERROR</head><body><p>Something went wrong. Uploaded file is empty.</p></body></hhtml>");
|
||||
request->send(200, "text/html", "<html><head>ERROR</head><body><p>Something went wrong (probably ESP32 out of memory). Uploaded file is empty.</p></body></hhtml>");
|
||||
else {
|
||||
String f = request->getParam(0)->value();
|
||||
request->redirect("/edit.html?file=" + f);
|
||||
|
@ -1368,8 +1439,6 @@ void initTouch() {
|
|||
}
|
||||
}
|
||||
|
||||
char buffer[85];
|
||||
MicroNMEA nmea(buffer, sizeof(buffer));
|
||||
|
||||
|
||||
|
||||
|
@ -1781,6 +1850,7 @@ int scanI2Cdevice(void)
|
|||
|
||||
extern int initlevels[40];
|
||||
|
||||
extern xSemaphoreHandle globalLock;
|
||||
|
||||
#ifdef ESP_MEM_DEBUG
|
||||
typedef void (*esp_alloc_failed_hook_t) (size_t size, uint32_t caps, const char * function_name);
|
||||
|
@ -1865,7 +1935,14 @@ void setup()
|
|||
Serial.println("AXP192 Begin FAIL");
|
||||
}
|
||||
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON);
|
||||
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON);
|
||||
if(sonde.config.type == TYPE_M5_CORE2) {
|
||||
// Display backlight on M5 Core2
|
||||
axp.setPowerOutPut(AXP192_DCDC3, AXP202_ON);
|
||||
axp.setDCDC3Voltage(3300);
|
||||
} else {
|
||||
// GPS on T-Beam, buzzer on M5 Core2
|
||||
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON);
|
||||
}
|
||||
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
|
||||
axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
|
||||
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
|
||||
|
@ -1980,9 +2057,30 @@ void setup()
|
|||
}
|
||||
// == show initial values from config.txt ========================= //
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
|
||||
if(sonde.config.type == TYPE_M5_CORE2) {
|
||||
// Core2 uses Pin 38 for MISO
|
||||
SPI.begin(18, 38, 23, -1);
|
||||
} else {
|
||||
SPI.begin();
|
||||
}
|
||||
//Set most significant bit first
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
//Divide the clock frequency
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
//Set data mode
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
|
||||
sx1278.setup(globalLock);
|
||||
|
||||
uint8_t state = 2;
|
||||
int i=0;
|
||||
while(++i<3) {
|
||||
delay(500);
|
||||
// == check the radio chip by setting default frequency =========== //
|
||||
if (rs41.setFrequency(402700000) == 0) {
|
||||
sx1278.ON();
|
||||
if (sx1278.setFrequency(402700000) == 0) {
|
||||
Serial.println(F("Setting freq: SUCCESS "));
|
||||
} else {
|
||||
Serial.println(F("Setting freq: ERROR "));
|
||||
|
@ -1991,6 +2089,7 @@ void setup()
|
|||
Serial.print("Frequency set to ");
|
||||
Serial.println(f);
|
||||
// == check the radio chip by setting default frequency =========== //
|
||||
}
|
||||
#endif
|
||||
|
||||
//sx1278.setLNAGain(-48);
|
||||
|
@ -2064,9 +2163,12 @@ void enterMode(int mode) {
|
|||
// trigger activation of background task
|
||||
// currentSonde should be set before enterMode()
|
||||
rxtask.activate = ACT_SONDE(sonde.currentSonde);
|
||||
//
|
||||
Serial.println("clearing and updating display");
|
||||
sonde.clearDisplay();
|
||||
sonde.updateDisplay();
|
||||
}
|
||||
printf("enterMode ok\n");
|
||||
}
|
||||
|
||||
static char text[40];
|
||||
|
@ -2233,7 +2335,9 @@ void loopDecoder() {
|
|||
}
|
||||
#endif
|
||||
} else {
|
||||
#if FEATURE_SONDEHUB
|
||||
sondehub_finish_data(&shclient, s, &sonde.config.sondehub);
|
||||
#endif
|
||||
}
|
||||
// always send data, even if not valid....
|
||||
if (rdzclient.connected()) {
|
||||
|
@ -2435,8 +2539,8 @@ void enableNetwork(bool enable) {
|
|||
#endif
|
||||
#if FEATURE_SONDEHUB
|
||||
if (sonde.config.sondehub.active && wifi_state != WIFI_APMODE) {
|
||||
time_last_update = millis() + 1000; /* force sending update */
|
||||
sondehub_station_update(&shclient, &sonde.config.sondehub);
|
||||
time_last_update = millis();
|
||||
}
|
||||
#endif
|
||||
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
|
||||
|
@ -2445,6 +2549,7 @@ void enableNetwork(bool enable) {
|
|||
MDNS.end();
|
||||
connected = false;
|
||||
}
|
||||
Serial.println("enableNetwork done");
|
||||
}
|
||||
|
||||
// Events used only for debug output right now
|
||||
|
@ -2686,7 +2791,7 @@ void loopTouchCalib() {
|
|||
// 2: access point mode in background. directly start initial mode (spectrum or scanner)
|
||||
// 3: traditional sync. WifiScan. Tries to connect to a network, in case of failure activates AP.
|
||||
// Mode 3 shows more debug information on serial port and display.
|
||||
#define MAXWIFIDELAY 20
|
||||
#define MAXWIFIDELAY 40
|
||||
static const char* _scan[2] = {"/", "\\"};
|
||||
void loopWifiScan() {
|
||||
if (sonde.config.wifi == 0) { // no Wifi
|
||||
|
@ -2701,6 +2806,7 @@ void loopWifiScan() {
|
|||
}
|
||||
if (sonde.config.wifi == 2) { // AP mode, setup in background
|
||||
startAP();
|
||||
enableNetwork(true);
|
||||
initialMode();
|
||||
return;
|
||||
}
|
||||
|
@ -2741,17 +2847,6 @@ void loopWifiScan() {
|
|||
while (WiFi.status() != WL_CONNECTED && cnt < MAXWIFIDELAY) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
#if 0
|
||||
if (cnt == 5) {
|
||||
// my FritzBox needs this for reconnecting
|
||||
WiFi.disconnect(true);
|
||||
delay(500);
|
||||
WiFi.begin(fetchWifiSSID(index), fetchWifiPw(index));
|
||||
Serial.print("Reconnecting to: "); Serial.print(fetchWifiSSID(index));
|
||||
Serial.print(" with password "); Serial.println(fetchWifiPw(index));
|
||||
delay(500);
|
||||
}
|
||||
#endif
|
||||
disp.rdis->drawString(15 * dispxs, lastl + dispys, _scan[cnt & 1]);
|
||||
cnt++;
|
||||
}
|
||||
|
@ -3005,17 +3100,8 @@ void loop() {
|
|||
|
||||
#if FEATURE_SONDEHUB
|
||||
if (sonde.config.sondehub.active) {
|
||||
unsigned long time_now = millis();
|
||||
// time_delta will be correct, even if time_now overflows
|
||||
unsigned long time_delta = time_now - time_last_update;
|
||||
if ((sonde.config.sondehub.chase == 0) && (time_delta >= SONDEHUB_STATION_UPDATE_TIME) && (wifi_state != WIFI_APMODE)) { // 60 min
|
||||
sondehub_station_update(&shclient, &sonde.config.sondehub);
|
||||
time_last_update = time_now;
|
||||
}
|
||||
else if ((sonde.config.sondehub.chase == 1) && (time_delta >= SONDEHUB_MOBILE_STATION_UPDATE_TIME) && (wifi_state != WIFI_APMODE)) { // 30 sec
|
||||
sondehub_station_update(&shclient, &sonde.config.sondehub);
|
||||
time_last_update = time_now;
|
||||
}
|
||||
// interval check moved to sondehub_station_update to avoid having to calculate distance in auto mode twice
|
||||
sondehub_station_update(&shclient, &sonde.config.sondehub);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -3025,12 +3111,33 @@ void loop() {
|
|||
/*
|
||||
Update station data to the sondehub v2 DB
|
||||
*/
|
||||
/* which_pos: 0=none, 1=fixed, 2=gps */
|
||||
void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) {
|
||||
#define STATION_DATA_LEN 300
|
||||
char data[STATION_DATA_LEN];
|
||||
char *w;
|
||||
|
||||
// If there is no connection to some WiFi AP, we cannot upload any data at all....
|
||||
if ( wifi_state != WIFI_CONNECTED ) return;
|
||||
|
||||
unsigned long time_now = millis();
|
||||
// time_delta will be correct, even if time_now overflows
|
||||
unsigned long time_delta = time_now - time_last_update;
|
||||
|
||||
int chase = conf->chase;
|
||||
// automatically decided if CHASE or FIXED mode is used (for config AUTO)
|
||||
if (chase == SH_LOC_AUTO) {
|
||||
if (SH_LOC_AUTO_IS_CHASE) chase = SH_LOC_CHASE; else chase = SH_LOC_FIXED;
|
||||
}
|
||||
|
||||
// Use 30sec update time in chase mode, 60 min in station mode.
|
||||
unsigned long update_time = (chase == SH_LOC_CHASE) ? SONDEHUB_MOBILE_STATION_UPDATE_TIME : SONDEHUB_STATION_UPDATE_TIME;
|
||||
|
||||
// If it is not yet time to send another update. do nothing....
|
||||
if ( (time_delta <= update_time) ) return;
|
||||
|
||||
Serial.println("sondehub_station_update()");
|
||||
time_last_update = time_now;
|
||||
|
||||
if (!client->connected()) {
|
||||
if (!client->connect(conf->host, 80)) {
|
||||
|
@ -3040,7 +3147,7 @@ void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) {
|
|||
}
|
||||
|
||||
w = data;
|
||||
memset(w, 0, STATION_DATA_LEN);
|
||||
// not necessary... memset(w, 0, STATION_DATA_LEN);
|
||||
|
||||
sprintf(w,
|
||||
"{"
|
||||
|
@ -3050,31 +3157,35 @@ void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) {
|
|||
"\"uploader_contact_email\": \"%s\",",
|
||||
version_name, version_id, conf->callsign, conf->email);
|
||||
w += strlen(w);
|
||||
if ((conf->chase == 0) && (conf->lat[0] != '\0') && (conf->lon[0] != '\0')) {
|
||||
if (conf->alt[0] != '\0') {
|
||||
|
||||
// We send GPS position: (a) in CHASE mode, (b) in FIXED mode if no fixed location has been specified in config
|
||||
if (chase == SH_LOC_CHASE || (chase == SH_LOC_FIXED && (isnan(conf->lat) || isnan(conf->lon)) ) ) {
|
||||
if (gpsPos.valid && gpsPos.lat != 0 && gpsPos.lon != 0) {
|
||||
sprintf(w,
|
||||
"\"uploader_position\": [%s,%s,%s],"
|
||||
"\"uploader_antenna\": \"%s\""
|
||||
"\"uploader_position\": [%.6f,%.6f,%d],"
|
||||
"\"uploader_antenna\": \"%s\","
|
||||
"\"mobile\": true"
|
||||
"}",
|
||||
conf->lat, conf->lon, conf->alt, conf->antenna);
|
||||
} else {
|
||||
sprintf(w,
|
||||
"\"uploader_position\": [%s,%s,null],"
|
||||
"\"uploader_antenna\": \"%s\""
|
||||
"}",
|
||||
conf->lat, conf->lon, conf->antenna);
|
||||
gpsPos.lat, gpsPos.lon, gpsPos.alt, conf->antenna);
|
||||
}
|
||||
}
|
||||
else if (gpsPos.valid && gpsPos.lat != 0 && gpsPos.lon != 0) {
|
||||
sprintf(w,
|
||||
"\"uploader_position\": [%.6f,%.6f,%d],"
|
||||
"\"uploader_antenna\": \"%s\","
|
||||
"\"mobile\": true"
|
||||
"}",
|
||||
gpsPos.lat, gpsPos.lon, gpsPos.alt, conf->antenna);
|
||||
// Otherweise, in FIXED mode we send the fixed position from config (if specified)
|
||||
else if (chase == SH_LOC_FIXED) {
|
||||
if ((!isnan(conf->lat)) && (!isnan(conf->lon))) {
|
||||
sprintf(w,
|
||||
"\"uploader_position\": [%.6f,%.6f,%s],"
|
||||
"\"uploader_antenna\": \"%s\""
|
||||
"}",
|
||||
conf->lat, conf->lon, conf->alt[0] ? conf->alt : "null", conf->antenna);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
// otherwise (in SH_LOC_NONE mode) we dont include any position info
|
||||
sprintf(w,
|
||||
"\"uploader_position\": [null,null,null],"
|
||||
"\"uploader_antenna\": \"%s\""
|
||||
"}",
|
||||
conf->antenna);
|
||||
}
|
||||
|
||||
client->println("PUT /listeners HTTP/1.1");
|
||||
|
@ -3092,7 +3203,7 @@ void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) {
|
|||
String response = client->readString();
|
||||
Serial.println(response);
|
||||
Serial.println("Response done...");
|
||||
//client->stop();r
|
||||
//client->stop();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3118,7 +3229,7 @@ const char *dfmSubtypeStrSH[16] = { NULL, NULL, NULL, NULL, NULL, NULL,
|
|||
|
||||
// in hours.... max allowed diff UTC <-> sonde time
|
||||
#define SONDEHUB_TIME_THRESHOLD (3)
|
||||
void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf) {
|
||||
void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub * conf) {
|
||||
Serial.println("sondehub_send_data()");
|
||||
Serial.printf("shState = %d\n", shState);
|
||||
|
||||
|
@ -3129,6 +3240,10 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co
|
|||
char rs_msg[MSG_SIZE];
|
||||
char *w;
|
||||
struct tm ts;
|
||||
uint8_t realtype = s->type;
|
||||
// config setting M10 and M20 will both decode both types, so use the real type that was decoded
|
||||
if(TYPE_IS_METEO(realtype)) { realtype = s->subtype==1 ? STYPE_M10 : STYPE_M20; }
|
||||
|
||||
// For DFM, s->time is data from subframe DAT8 (gps date/hh/mm), and sec is from DAT1 (gps sec/usec)
|
||||
// For all others, sec should always be 0 and time the exact time in seconds
|
||||
time_t t = s->time + s->sec;
|
||||
|
@ -3158,7 +3273,7 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co
|
|||
if (((int)s->lat == 0) && ((int)s->lon == 0)) return; // Sometimes these values are zeroes. Don't send those to the sondehub
|
||||
if ((int)s->alt > 50000) return; // If alt is too high don't send to SondeHub
|
||||
// M20 data does not include #sat information
|
||||
if ( s->type != STYPE_M20 && (int)s->sats < 4) return; // If not enough sats don't send to SondeHub
|
||||
if ( realtype != STYPE_M20 && (int)s->sats < 4) return; // If not enough sats don't send to SondeHub
|
||||
|
||||
// If not connected to sondehub, try reconnecting.
|
||||
// TODO: do this outside of main loop
|
||||
|
@ -3185,7 +3300,7 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co
|
|||
|
||||
// DFM uses UTC. Most of the other radiosondes use GPS time
|
||||
// SondeHub expect datetime to be the same time sytem as the sonde transmits as time stamp
|
||||
if ( s->type == STYPE_RS41 || s->type == STYPE_RS92 || s->type == STYPE_M20 ) {
|
||||
if ( realtype == STYPE_RS41 || realtype == STYPE_RS92 || realtype == STYPE_M20 ) {
|
||||
t += 18; // convert back to GPS time from UTC time +18s
|
||||
}
|
||||
|
||||
|
@ -3213,25 +3328,25 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co
|
|||
"\"rssi\": %.1f,",
|
||||
version_name, version_id, conf->callsign,
|
||||
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
|
||||
manufacturer_string[s->type], s->ser,
|
||||
manufacturer_string[realtype], s->ser,
|
||||
ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec + s->sec,
|
||||
(float)s->lat, (float)s->lon, (float)s->alt, (float)s->freq, (float)s->hs, (float)s->vs,
|
||||
(float)s->dir, -((float)s->rssi / 2)
|
||||
);
|
||||
w += strlen(w);
|
||||
|
||||
if (s->type != STYPE_M20) {
|
||||
|
||||
if (realtype != STYPE_M20) {
|
||||
sprintf(w, "\"sats\": %d,", (int)s->sats);
|
||||
w += strlen(w);
|
||||
}
|
||||
|
||||
if ( TYPE_IS_DFM(s->type) || TYPE_IS_METEO(s->type) || s->type == STYPE_MP3H ) {
|
||||
if ( TYPE_IS_DFM(realtype) || TYPE_IS_METEO(realtype) || realtype == STYPE_MP3H ) {
|
||||
// send frame as gps timestamp for these sonde, identical to autorx
|
||||
// For M10, this is real GPS time (seconds since Jqn 6 1980, without adjusting for leap seconds)
|
||||
// DFM and MP3H send real UTC (with leap seconds considered), so for them the frame number actually
|
||||
// is gps time plus number of leap seconds since the beginning of GPS time.
|
||||
int frame = (int)(t - 315964800);
|
||||
if (s->type == STYPE_M10) {
|
||||
if (realtype == STYPE_M10) {
|
||||
frame += 18;
|
||||
};
|
||||
sprintf(w, "\"frame\": %d,", frame);
|
||||
|
@ -3240,7 +3355,7 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co
|
|||
}
|
||||
w += strlen(w);
|
||||
|
||||
sprintf(w, "\"type\": \"%s\",", sondeTypeStrSH[s->type]);
|
||||
sprintf(w, "\"type\": \"%s\",", sondeTypeStrSH[realtype]);
|
||||
w += strlen(w);
|
||||
|
||||
/* if there is a subtype (DFM only) */
|
||||
|
@ -3261,17 +3376,17 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co
|
|||
w += strlen(w);
|
||||
}
|
||||
|
||||
if ((conf->chase == 0) && (conf->lat[0] != '\0') && (conf->lon[0] != '\0')) {
|
||||
if ((conf->chase == 0) && (!isnan(conf->lat)) && (!isnan(conf->lon))) {
|
||||
if (conf->alt[0] != '\0') {
|
||||
sprintf(w,
|
||||
"\"uploader_position\": [%s,%s,%s],"
|
||||
"\"uploader_position\": [%.6f,%.6f,%s],"
|
||||
"\"uploader_antenna\": \"%s\""
|
||||
"}",
|
||||
conf->lat, conf->lon, conf->alt, conf->antenna
|
||||
);
|
||||
} else {
|
||||
sprintf(w,
|
||||
"\"uploader_position\": [%s,%s,null],"
|
||||
"\"uploader_position\": [%.6f,%.6f,null],"
|
||||
"\"uploader_antenna\": \"%s\""
|
||||
"}",
|
||||
conf->lat, conf->lon, conf->antenna
|
||||
|
@ -3312,7 +3427,7 @@ void sondehub_send_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *co
|
|||
//Serial.println(response);
|
||||
}
|
||||
|
||||
void sondehub_finish_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf) {
|
||||
void sondehub_finish_data(WiFiClient * client, SondeInfo * s, struct st_sondehub * conf) {
|
||||
// If there is an "old" pending collection of JSON data sets, send it even if no now data is received
|
||||
if (shState == SH_CONN_APPENDING) {
|
||||
time_t now;
|
||||
|
@ -3325,7 +3440,7 @@ void sondehub_finish_data(WiFiClient *client, SondeInfo *s, struct st_sondehub *
|
|||
}
|
||||
}
|
||||
|
||||
void sondehub_send_header(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf) {
|
||||
void sondehub_send_header(WiFiClient * client, SondeInfo * s, struct st_sondehub * conf) {
|
||||
Serial.print("PUT /sondes/telemetry HTTP/1.1\r\n"
|
||||
"Host: ");
|
||||
Serial.println(conf->host);
|
||||
|
@ -3339,7 +3454,7 @@ void sondehub_send_header(WiFiClient *client, SondeInfo *s, struct st_sondehub *
|
|||
"Content-Type: application/json\r\n"
|
||||
"Transfer-Encoding: chunked\r\n");
|
||||
}
|
||||
void sondehub_send_next(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf, char *chunk, int chunklen, int first) {
|
||||
void sondehub_send_next(WiFiClient * client, SondeInfo * s, struct st_sondehub * conf, char *chunk, int chunklen, int first) {
|
||||
// send next chunk of JSON request
|
||||
client->printf("%x\r\n", chunklen + 1);
|
||||
client->write(first ? "[" : ",", 1);
|
||||
|
@ -3347,11 +3462,11 @@ void sondehub_send_next(WiFiClient *client, SondeInfo *s, struct st_sondehub *co
|
|||
client->print("\r\n");
|
||||
|
||||
Serial.printf("%x\r\n", chunklen + 1);
|
||||
Serial.write(first ? "[" : ",", 1);
|
||||
Serial.write(chunk, chunklen);
|
||||
Serial.write((const uint8_t *)(first ? "[" : ","), 1);
|
||||
Serial.write((const uint8_t *)chunk, chunklen);
|
||||
Serial.print("\r\n");
|
||||
}
|
||||
void sondehub_send_last(WiFiClient *client, SondeInfo *s, struct st_sondehub *conf) {
|
||||
void sondehub_send_last(WiFiClient * client, SondeInfo * s, struct st_sondehub * conf) {
|
||||
// last chunk. just the closing "]" of the json request
|
||||
client->printf("1\r\n]\r\n0\r\n\r\n");
|
||||
Serial.printf("1\r\n]\r\n0\r\n\r\n");
|
||||
|
|
|
@ -25,11 +25,9 @@
|
|||
#tft_rs=2
|
||||
#tft_cs=0
|
||||
tft_orient=1
|
||||
#tft_modeflip=0
|
||||
#tft_spifreq=40000000
|
||||
#gps_rxd=-1
|
||||
#gps_txd=-1
|
||||
# Show AFC value (for RS41 and M10/M20, maybe also DFM, but not useful for RS92)
|
||||
showafc=1
|
||||
# Frequency correction, in Hz
|
||||
# freqofs=0
|
||||
#-------------------------------#
|
||||
|
@ -42,8 +40,8 @@ wifi=3
|
|||
# TCP/IP KISS TNC in port 14590 for APRSdroid (0=disabled, 1=enabled)
|
||||
kisstnc.active = 1
|
||||
|
||||
# which screens file to use (0: screens.txt, i>0: screens${i}.txt
|
||||
# 0: old version; 1: for OLED, 2: for TFT; 3: for TFT (portrait mode)
|
||||
# which screens file to use (0: automated selection based on display type and orientation, i>0: screens${i}.txt
|
||||
# predefined: 1: for OLED, 2: for ILI9225; 3: for ILI9225 (portrait mode); 4: for ILI9431; 5: for ILI9431 (portrait mode)
|
||||
# screenfile=2
|
||||
# display configuration. List of "displays"
|
||||
# first entry: "Scanner" display
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<button class="tablinks" onclick="selTab(event,'QRG')" id="defaultTab">QRG</button>
|
||||
<button class="tablinks" onclick="selTab(event,'WiFi')">WiFi</button>
|
||||
<button class="tablinks" onclick="selTab(event,'Data')">Data</button>
|
||||
<button class="tablinks" onclick="document.location.href='livemap.html'">LiveMap</button>
|
||||
<button class="tablinks" onclick="selTab(event,'Map')">Map</button>
|
||||
<button class="tablinks" onclick="selTab(event,'Config')">Config</button>
|
||||
<button class="tablinks" onclick="selTab(event,'Control')">Control</button>
|
||||
|
@ -51,6 +52,9 @@
|
|||
%VERSION_NAME%<br>
|
||||
Copyright © 2019-2021 by Hansi Reiser, DL9RDZ<br>
|
||||
(version %VERSION_ID%)<br><br>
|
||||
|
||||
<a href="/update.html">Check for update (requires TTGO internet connection via WiFi)</a><br><br>
|
||||
|
||||
with contributions by Vigor and Xavier (M20 support),
|
||||
<a href="https://github.com/LukePrior">Luke Prior</a> and <a href="https://github.com/oh3bsg">OH3BSG</a> (SondeHub support),
|
||||
<a href="https://www.dl2mf.de/" target="_blank">Meinhard Guenther, DL2MF</a>,
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>rdzTTGOSonde Server LiveMap</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
|
||||
<script src="https://unpkg.com/leaflet.marker.slideto@0.2.0/Leaflet.Marker.SlideTo.js"></script>
|
||||
<script src="livemap.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,478 @@
|
|||
$(document).ready(function(){
|
||||
|
||||
var map = L.map('map', { attributionControl: false, zoomControl: false });
|
||||
map.on('mousedown touchstart',function () { follow=false; });
|
||||
|
||||
L.control.scale().addTo(map);
|
||||
L.control.attribution({prefix:false}).addTo(map);
|
||||
|
||||
var osm = L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
|
||||
attribution: '<div><a href="https://leafletjs.com/">Leaflet</a> · Map: <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a></div>',
|
||||
minZoom: 1,
|
||||
maxZoom: 19
|
||||
});
|
||||
var esri = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
||||
attribution: '<div><a href="https://leafletjs.com/">Leaflet</a> · Map: <a href="https://www.esri.com/">Esri</a> · Earthstar Geographics</div>',
|
||||
minZoom: 1,
|
||||
maxZoom: 20
|
||||
});
|
||||
|
||||
var basemap = 'osm';
|
||||
osm.addTo(map);
|
||||
|
||||
basemap_change = function () {
|
||||
if (basemap == 'osm') {
|
||||
map.removeLayer(osm);
|
||||
map.addLayer(esri);
|
||||
basemap = 'esri';
|
||||
} else {
|
||||
map.removeLayer(esri);
|
||||
map.addLayer(osm);
|
||||
basemap = 'osm';
|
||||
}
|
||||
};
|
||||
|
||||
map.setView([51.163361,10.447683], 5); // Mitte DE
|
||||
|
||||
var reddot = '<span class="ldot rbg"></span> ';
|
||||
var yellowdot = '<span class="ldot ybg"></span> ';
|
||||
var greendot = '<span class="ldot gbg"></span> ';
|
||||
|
||||
$('#map .leaflet-control-container').append(L.DomUtil.create('div', 'leaflet-top leaflet-center leaflet-header'));
|
||||
var header = '';
|
||||
header += '<div id="sonde_main"><b>rdzTTGOSonde LiveMap</b><br />🎈 <b><span id="sonde_id"></span> - <span id="sonde_freq"></span> MHz - <span id="sonde_type"></span></b></div>';
|
||||
header += '<div id="sonde_detail"><span id="sonde_alt"></span>m | <span id="sonde_climb"></span>m/s | <span id="sonde_speed"></span>km/h</div>';
|
||||
header += '<div id="sonde_status"><small><span id="sonde_statbar"></span></small></div>';
|
||||
header += '<div id="settings"><br /><b>Prediction-Settings</b><br />';
|
||||
|
||||
header += '<label for="burst">Burst at:</label><input type="text" id="burst" maxlength="5" value="..." /> m<br />';
|
||||
header += '<label for="overwrite_descend">Descending:</label><input type="text" id="overwrite_descend" maxlength="2" value="..." /> m/s<br />';
|
||||
header += '<label for="overwrite_descend_till">Use this descending until:</label><input type="text" id="overwrite_descend_till" maxlength="5" value="..." /> m<br />';
|
||||
header += '<small>after the transmitted descend will be used</small>';
|
||||
header += '<div id="submit"><input type="button" value="save" onclick="settings_save();"/> <input type="button" id="submit" value="reset" onclick="settings_reset();"/></div>';
|
||||
header += '</div>';
|
||||
$('.leaflet-header').append(header);
|
||||
|
||||
|
||||
$('#map .leaflet-control-container').append(L.DomUtil.create('div', 'leaflet-bottom leaflet-center leaflet-footer'));
|
||||
var footer = '';
|
||||
footer += '<div id="gps_main"><b>Direction: </b><span class="gps_dir">...</span>°<br /><b>Distance: </b><span class="gps_dist">...</span>m</div>';
|
||||
$('.leaflet-footer').append(footer);
|
||||
|
||||
var statbar = '';
|
||||
headtxt = function(data,stat) {
|
||||
//var staticon = (stat == '1')?'🟢':'🟡';
|
||||
var staticon = (stat == '1')?greendot:yellowdot;
|
||||
statbar = staticon + statbar;
|
||||
if ((statbar.length) > 10*greendot.length) { statbar = statbar.substring(0,10*greendot.length); }
|
||||
if (data.lat == '0.000000') { return false; }
|
||||
if (data.id) {
|
||||
$('#sonde_id').html(data.id);
|
||||
$('#sonde_alt').html(data.alt);
|
||||
$('#sonde_climb').html(data.climb);
|
||||
$('#sonde_speed').html( mr(data.speed * 3.6 * 10) / 10 );
|
||||
$('#sonde_detail').show();
|
||||
} else {
|
||||
$('#sonde_id').html(data.launchsite.trim());
|
||||
$('#sonde_detail').hide();
|
||||
}
|
||||
$('#sonde_freq').html(data.freq);
|
||||
$('#sonde_type').html(data.type);
|
||||
$('#sonde_statbar').html(' '+statbar);
|
||||
};
|
||||
|
||||
map.addControl(new L.Control.Button([ { position: 'topleft', text: '🔙', href: 'index.html' } ]));
|
||||
|
||||
L.control.zoom({ position:'topleft' }).addTo(map);
|
||||
|
||||
map.addControl(new L.Control.Button([ { position: 'topleft', text: '🗺️', href: 'javascript:basemap_change();' } ]));
|
||||
|
||||
map.addControl(new L.Control.Button([ { position: 'topright', id: "status", text: '🔴', href: 'javascript:get_data();' } ]));
|
||||
|
||||
map.addControl(new L.Control.Button([
|
||||
{ position:'topright', text: '🎈', href: 'javascript:show(marker,\'marker\');' },
|
||||
{ text: '〰️', href: 'javascript:show_line();' },
|
||||
{ text: '💥', href: 'javascript:show(marker_burst,\'burst\');' },
|
||||
{ text: '🎯', href: 'javascript:show(marker_landing,\'landing\');' }
|
||||
]));
|
||||
|
||||
map.addControl(new L.Control.Button([ { position:'topright', text: '⚙️', href: 'javascript:show_settings();' } ]));
|
||||
|
||||
|
||||
show = function(e,p) {
|
||||
if (p == 'landing') { get_predict(last_data); }
|
||||
if (e) {
|
||||
map.closePopup();
|
||||
map.setView(map._layers[e._leaflet_id].getLatLng());
|
||||
map._layers[e._leaflet_id].openPopup();
|
||||
follow = p;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
getTwoBounds = function (a,b) {
|
||||
var sW = new L.LatLng((a._southWest.lat > b._southWest.lat)?b._southWest.lat:a._southWest.lat, (a._southWest.lng > b._southWest.lng)?b._southWest.lng:a._southWest.lng);
|
||||
var nE = new L.LatLng((a._northEast.lat < b._northEast.lat)?b._northEast.lat:a._northEast.lat, (a._northEast.lng < b._northEast.lng)?b._northEast.lng:a._northEast.lng);
|
||||
|
||||
return new L.LatLngBounds(sW, nE);
|
||||
};
|
||||
|
||||
show_line = function() {
|
||||
$('.i_position, .i_landing').remove();
|
||||
map.closePopup();
|
||||
if (line._latlngs.length != 0 && line_predict._latlngs.length != 0) {
|
||||
map.fitBounds(getTwoBounds(line.getBounds(),line_predict.getBounds()));
|
||||
} else if (line._latlngs.length != 0) {
|
||||
map.fitBounds(line.getBounds());
|
||||
} else if (line_predict._latlngs.length != 0) {
|
||||
map.fitBounds(line_predict.getBounds());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
last_data = false;
|
||||
follow = 'marker';
|
||||
|
||||
marker_landing = false;
|
||||
icon_landing = L.divIcon({className: 'leaflet-landing'});
|
||||
dots_predict = [];
|
||||
line_predict = L.polyline(dots_predict,{color: 'yellow'}).addTo(map);
|
||||
marker_burst = false;
|
||||
icon_burst = L.divIcon({className: 'leaflet-burst'});
|
||||
|
||||
marker = false;
|
||||
dots = [];
|
||||
line = L.polyline(dots).addTo(map);
|
||||
|
||||
draw = function(data) {
|
||||
var stat;
|
||||
if (data.id) {
|
||||
|
||||
if ((data.lat != '0.000000' && data.lon != '0.000000') && (JSON.stringify(data) != JSON.stringify(last_data)) ) {
|
||||
var location = [data.lat,data.lon,data.alt];
|
||||
if (!marker) {
|
||||
map.setView(location, 14);
|
||||
marker = L.marker(location).addTo(map)
|
||||
.bindPopup(poptxt('position',data),{closeOnClick:false, autoPan:false}).openPopup();
|
||||
get_predict(data);
|
||||
} else {
|
||||
marker.slideTo(location, {
|
||||
duration: 500,
|
||||
keepAtCenter: (follow=='marker')?true:false
|
||||
})
|
||||
.setPopupContent(poptxt('position',data));
|
||||
if (last_data.id != data.id) {
|
||||
storage_remove();
|
||||
dots = [];
|
||||
get_predict(data);
|
||||
}
|
||||
}
|
||||
dots.push(location);
|
||||
line.setLatLngs(dots);
|
||||
storage_write(data);
|
||||
//$('#status').html('🟢');
|
||||
$('#status').html(greendot);
|
||||
stat = 1;
|
||||
} else {
|
||||
//$('#status').html('🟡');
|
||||
$('#status').html(yellowdot);
|
||||
stat = 0;
|
||||
}
|
||||
headtxt(data,stat);
|
||||
last_data = data;
|
||||
} else {
|
||||
//$('#status').html('🟡');
|
||||
$('#status').html(yellowdot);
|
||||
headtxt(data,0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
marker_gps = false;
|
||||
icon_gps = L.divIcon({className: 'leaflet-gps'});
|
||||
circ_gps = false;
|
||||
|
||||
gps = function(e) {
|
||||
gps_location = [e.lat/1000000,e.lon/1000000];
|
||||
gps_accuracy = e.hdop*2;
|
||||
|
||||
if (last_data && last_data.lat != '0.000000') {
|
||||
if ($('.leaflet-footer').css('display') == 'none') { $('.leaflet-footer').show(); }
|
||||
|
||||
var distance = Math.round(map.distance(gps_location,[last_data.lat, last_data.lon]));
|
||||
distance = (distance > 1000)?(distance / 1000) + 'k':distance;
|
||||
$('.leaflet-footer .gps_dist').html(distance);
|
||||
|
||||
$('.leaflet-footer .gps_dir').html( bearing(gps_location,[last_data.lat, last_data.lon]) );
|
||||
}
|
||||
|
||||
if (!marker_gps) {
|
||||
map.addControl(new L.Control.Button([{ position: 'topleft', text: '🛰️', href: 'javascript:show(marker_gps,\'gps\');' }]));
|
||||
|
||||
marker_gps = L.marker(gps_location,{icon:icon_gps}).addTo(map)
|
||||
.bindPopup(poptxt('gps',e),{closeOnClick:false, autoPan:false});
|
||||
circ_gps = L.circle(gps_location, gps_accuracy).addTo(map);
|
||||
} else {
|
||||
marker_gps.slideTo(gps_location, {
|
||||
duration: 500,
|
||||
keepAtCenter: (follow=='gps')?true:false
|
||||
})
|
||||
.setPopupContent(poptxt('gps',e));
|
||||
circ_gps.slideTo(gps_location, { duration: 500 });
|
||||
circ_gps.setRadius(gps_accuracy);
|
||||
}
|
||||
};
|
||||
|
||||
get_data = function() {
|
||||
//$('#status').html('🔴');
|
||||
$('#status').html(reddot);
|
||||
$.ajax({url: 'live.json', success: (function( data ) {
|
||||
if (typeof data != "object") { data = $.parseJSON(data); }
|
||||
if (data.sonde) {
|
||||
draw(data.sonde);
|
||||
} else {
|
||||
//setTimeout(function() {$('#status').html('🟡');},100);
|
||||
setTimeout(function() {$('#status').html(yellowdot);},100);
|
||||
}
|
||||
if (data.gps) {
|
||||
gps(data.gps);
|
||||
}
|
||||
}),
|
||||
timeout: 1000}
|
||||
);
|
||||
};
|
||||
|
||||
storage = (typeof(Storage) !== "undefined")?true:false;
|
||||
|
||||
settings_std = {
|
||||
burst: 32500,
|
||||
overwrite_descend: 6,
|
||||
overwrite_descend_till: 12000
|
||||
};
|
||||
|
||||
settings_read = function() {
|
||||
if (storage) {
|
||||
if (sessionStorage.settings) {
|
||||
return JSON.parse(sessionStorage.settings);
|
||||
} else {
|
||||
settings_write(settings_std);
|
||||
return settings_std;
|
||||
}
|
||||
} else {
|
||||
return settings_std;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
settings_write = function (data) {
|
||||
if (storage) {
|
||||
sessionStorage.settings = JSON.stringify(data);
|
||||
settings = data;
|
||||
}
|
||||
};
|
||||
|
||||
settings = settings_read();
|
||||
|
||||
settings_save = function() {
|
||||
settings.burst = parseInt($('#settings #burst').val());
|
||||
settings.overwrite_descend = parseInt($('#settings #overwrite_descend').val());
|
||||
settings.overwrite_descend_till = parseInt($('#settings #overwrite_descend_till').val());
|
||||
if (Number.isInteger(settings.burst) && Number.isInteger(settings.overwrite_descend) && Number.isInteger(settings.overwrite_descend_till)) {
|
||||
settings_write(settings);
|
||||
$("#settings").slideUp();
|
||||
get_predict(last_data);
|
||||
} else {
|
||||
alert('Error: only numeric values allowed!');
|
||||
}
|
||||
};
|
||||
|
||||
settings_reset = function() {
|
||||
if (confirm('Reset to default?')) {
|
||||
settings_write(settings_std);
|
||||
show_settings();
|
||||
}
|
||||
};
|
||||
|
||||
show_settings = function() {
|
||||
$('#settings #burst').val(settings.burst);
|
||||
$('#settings #overwrite_descend').val(settings.overwrite_descend);
|
||||
$('#settings #overwrite_descend_till').val(settings.overwrite_descend_till);
|
||||
$("#settings").slideToggle();
|
||||
};
|
||||
|
||||
predictor = false;
|
||||
get_predict = function(data) {
|
||||
if (!data) { return; }
|
||||
var ascent = (data.climb > 0)? data.climb : 15;
|
||||
var descent = (data.climb > 0)? settings.overwrite_descend : data.climb * -1;
|
||||
|
||||
var burst;
|
||||
if (data.climb > 0) {
|
||||
burst = (data.alt > settings.burst )?data.alt + 100 : settings.burst;
|
||||
} else {
|
||||
burst = parseInt(data.alt) + 7;
|
||||
if (data.alt > settings.overwrite_descend_till ) { descent = settings.overwrite_descend; }
|
||||
}
|
||||
|
||||
var m = new Date();
|
||||
var datetime = m.getUTCFullYear() + "-" + az(m.getUTCMonth()+1) + "-" + az(m.getUTCDate()) + "T" +
|
||||
az(m.getUTCHours()) + ":" + az(m.getUTCMinutes()) + ":" + az(m.getUTCSeconds()) + "Z";
|
||||
var url = 'https://predict.cusf.co.uk/api/v1/';
|
||||
url += '?launch_latitude='+data.lat + '&launch_longitude='+data.lon;
|
||||
url += '&launch_altitude='+data.alt + '&launch_datetime='+datetime;
|
||||
url += '&ascent_rate='+ascent + '&burst_altitude=' + burst + '&descent_rate='+descent;
|
||||
|
||||
$.getJSON(url, function( prediction ) {
|
||||
draw_predict(prediction,data);
|
||||
});
|
||||
};
|
||||
|
||||
draw_predict = function(prediction,data) {
|
||||
var ascending = prediction.prediction[0].trajectory;
|
||||
var highest = ascending[ascending.length-1];
|
||||
var highest_location = [highest.latitude,highest.longitude];
|
||||
|
||||
var descending = prediction.prediction[1].trajectory;
|
||||
var landing = descending[descending.length-1];
|
||||
var landing_location = [landing.latitude,landing.longitude];
|
||||
|
||||
if (!marker_landing) {
|
||||
marker_landing = L.marker(landing_location,{icon: icon_landing}).addTo(map)
|
||||
.bindPopup(poptxt('landing',landing),{closeOnClick:false, autoPan:false});
|
||||
} else {
|
||||
marker_landing.slideTo(landing_location, {
|
||||
duration: 500,
|
||||
keepAtCenter: (follow=='landing')?true:false
|
||||
})
|
||||
.setPopupContent(poptxt('landing',landing));
|
||||
}
|
||||
|
||||
dots_predict=[];
|
||||
|
||||
if (data.climb > 0) {
|
||||
ascending.forEach(p => dots_predict.push([p.latitude,p.longitude]));
|
||||
|
||||
if (!marker_burst) {
|
||||
marker_burst = L.marker(highest_location,{icon:icon_burst}).addTo(map).bindPopup(poptxt('burst',highest),{closeOnClick:false, autoPan:false});
|
||||
} else {
|
||||
marker_burst.slideTo(highest_location, {
|
||||
duration: 500,
|
||||
keepAtCenter: (follow=='burst')?true:false
|
||||
}).setPopupContent(poptxt('burst',highest));
|
||||
}
|
||||
}
|
||||
|
||||
descending.forEach(p => dots_predict.push([p.latitude,p.longitude]));
|
||||
line_predict.setLatLngs(dots_predict);
|
||||
|
||||
if (data.climb > 0) {
|
||||
predictor_time = 5 * 60; // ascending, every 5 min
|
||||
} else if (data.climb < 0 && data.alt > 5000) {
|
||||
predictor_time = 2 * 60; // descending, above 5km, every 2 min
|
||||
} else {
|
||||
predictor_time = 30; // descending, below 5km, every 30 sec
|
||||
}
|
||||
clearTimeout(predictor);
|
||||
predictor = setTimeout(function() {get_predict(last_data);}, predictor_time*1000);
|
||||
};
|
||||
|
||||
poptxt = function(t,i) {
|
||||
var lat_input = (i.id)?i.lat:i.latitude;
|
||||
var lon_input = (i.id)?i.lon:i.longitude;
|
||||
|
||||
var lat = Math.round(lat_input * 1000000) / 1000000;
|
||||
var lon = Math.round(lon_input * 1000000) / 1000000;
|
||||
|
||||
var add =
|
||||
'<br /><b>Position:</b> '+lat+', '+lon+'<br />'+
|
||||
'<b>Open:</b> <a href="https://www.google.de/maps/?q='+lat+', '+lon+'" target="_blank">GMaps</a> | <a href="https://www.openstreetmap.org/?mlat='+lat+'&mlon='+lon+'&zoom=15" target="_blank">OSM</a> | <a href="mapsme://map?ll='+lat+','+lon+'">Maps.me</a>';
|
||||
|
||||
if (t == 'position') { return '<div class="i_position"><b>🎈 '+i.id+'</b>'+add+'</div>'; }
|
||||
if (t == 'burst') { return '<div class="i_burst"><b>💥 Predicted Burst:</b><br />'+fd(i.datetime)+' in '+mr(i.altitude)+'m'+add+'</div>'; }
|
||||
if (t == 'highest') { return '<div class="i_burst"><b>💥 Burst:</b> '+mr(i.altitude)+'m'+add+'</div>';}
|
||||
if (t == 'landing') { return '<div class="i_landing"><b>🎯 Predicted Landing:</b><br />'+fd(i.datetime)+' at '+mr(i.altitude)+'m'+add+'</div>'; }
|
||||
if (t == 'gps') { return '<div class="i_gps">Position: '+(i.lat/1000000)+','+(i.lon/1000000)+'<br />Altitude: '+mr(i.alt/1000)+'m<br />Speed: '+mr(i.speed/1000 * 1.852 * 10)/10+'km/h '+mr(i.dir/1000)+'°<br />Sat: '+i.sat+' Hdop:'+(i.hdop/10)+'</div>'; }
|
||||
};
|
||||
|
||||
fd = function(date) {
|
||||
var d = new Date(Date.parse(date));
|
||||
return az(d.getUTCHours()) +':'+ az(d.getUTCMinutes())+' UTC';
|
||||
};
|
||||
az = function(n) { return (n<10)?'0'+n:n; };
|
||||
mr = function(n) { return Math.round(n); };
|
||||
|
||||
storage = (typeof(Storage) !== "undefined")?true:false;
|
||||
storage_write = function (data) {
|
||||
if (storage) {
|
||||
if (sessionStorage.sonde) {
|
||||
storage_data = JSON.parse(sessionStorage.sonde);
|
||||
} else {
|
||||
storage_data = [];
|
||||
}
|
||||
if (JSON.stringify(data) != JSON.stringify(storage_data[storage_data.length - 1])) {
|
||||
storage_data.push(data);
|
||||
sessionStorage.sonde = JSON.stringify(storage_data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
storage_read = function() {
|
||||
if (storage) {
|
||||
if (sessionStorage.sonde) {
|
||||
storage_data = JSON.parse(sessionStorage.sonde);
|
||||
return storage_data;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
storage_remove = function() {
|
||||
sessionStorage.removeItem('sonde');
|
||||
};
|
||||
|
||||
session_storage = storage_read();
|
||||
if (session_storage) {
|
||||
session_storage.forEach(function(d) {
|
||||
dots.push([d.lat,d.lon,d.alt]);
|
||||
session_storage_last = d;
|
||||
});
|
||||
draw(session_storage_last);
|
||||
}
|
||||
|
||||
setInterval(get_data,1000);
|
||||
|
||||
});
|
||||
|
||||
L.Control.Button = L.Control.extend({
|
||||
onAdd: function (map) {
|
||||
var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
|
||||
options = this.options;
|
||||
Object.keys(options).forEach(function(key) {
|
||||
this.link = L.DomUtil.create('a', '', container);
|
||||
this.link.text = options[key].text;
|
||||
this.link.href = options[key].href;
|
||||
this.link.id = options[key].id;
|
||||
});
|
||||
|
||||
this.options.position = this.options[0].position;
|
||||
return container;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// https://github.com/makinacorpus/Leaflet.GeometryUtil/blob/master/src/leaflet.geometryutil.js#L682
|
||||
// modified to fit
|
||||
function bearing(latlng1, latlng2) {
|
||||
var rad = Math.PI / 180,
|
||||
lat1 = latlng1[0] * rad,
|
||||
lat2 = latlng2[0] * rad,
|
||||
lon1 = latlng1[1] * rad,
|
||||
lon2 = latlng2[1] * rad,
|
||||
y = Math.sin(lon2 - lon1) * Math.cos(lat2),
|
||||
x = Math.cos(lat1) * Math.sin(lat2) -
|
||||
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
|
||||
var bearing = ((Math.atan2(y, x) * 180 / Math.PI) + 360) % 360;
|
||||
bearing = bearing < 0 ? bearing-360 : bearing;
|
||||
return Math.round(bearing);
|
||||
}
|
|
@ -0,0 +1,574 @@
|
|||
## screens2.txt: TFT display (landscape)
|
||||
# Definition of display content and action behaviour
|
||||
#
|
||||
# Timer: (view timer, rx timer, norx timer)
|
||||
# - value -1: timer is disabled; value>=0: timer fires after (value) seconds
|
||||
# - view timer: time since current view (display mode and sonde) was started
|
||||
# - rx timer: time since when sonde data has been received continuously (trigger immediatly after RX)
|
||||
# - norx timer: time since when no sonde data has been received continuously
|
||||
# (rx and norx timer is started after tuning a new frequency and receiving a signal or not receiving
|
||||
# anything for a 1s period)
|
||||
#
|
||||
# Actions:
|
||||
# - W: activate WiFi scan
|
||||
# - F: activate frequency spectrum display
|
||||
# - 0: activate "Scan:" display (this is basically just display mode 0)
|
||||
# - x: (1..N): activate display mode x [deprecated]
|
||||
# - >: activate next display mode
|
||||
# - D: activate default receiver display (display mode specified in config)
|
||||
# - +: advance to next active sonde from QRG config
|
||||
# - #: no action
|
||||
#
|
||||
# Display content (lower/upper case: small/large font)
|
||||
# line,column=content
|
||||
# for ILI9225 its also possible to indicate
|
||||
# line,column,width=content for text within a box of width 'width'
|
||||
# line,column,-width=content for right-justified text
|
||||
#
|
||||
# XText : Text
|
||||
# F(suffix): frequency (with suffix, e.g., " MHz")
|
||||
# L latitade
|
||||
# O lOngitute
|
||||
# A altitude
|
||||
# Hm(suffix) hor. speed m/s (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
||||
# Hk(suffix) hor. speed km/h (suffix: e.g. "km/h"; no suffix=>km/h as 16x8 bitmap for SSD1306 display only)
|
||||
# V(suffix) vert. speef (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
||||
# Ix sonde ID (default/d: dxlaprs; s: short id, n: real serial number)
|
||||
# RS41,RS92: all identical R1234567
|
||||
# DFMx: ID M12345678; short ID and serial 12345678
|
||||
# M10: ID ME95231F0; short ID: M95231F0; serial 9062104592
|
||||
# Q signal quality statistics bar
|
||||
# T type string (RS41/DFM9/DFM6/RS92)
|
||||
# C afC value
|
||||
# N ip address (only tiny font)
|
||||
# S scan list entry info: l/empty: launch site name, #=entry nr, t=total entries, a=active entries, /: #/t
|
||||
# K RS41 kill timer values: Kl launch timer, Kb burst timer, Kc kill countdown
|
||||
# format: K_4: h:mm k_6: h:mm:ss k_s: sssss, nothing shown for other sonde
|
||||
# Mx telemetry value x (t temp p preassure h hyg) [not yet implemented, maybe some day in future]
|
||||
# Gx GPS-related data
|
||||
# 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:
|
||||
# (y should be a 1x2 font (1,5,6,7), x a small font)
|
||||
# u8x8_font_chroma48medium8_r, // 0 ** default small
|
||||
# u8x8_font_7x14_1x2_f, // 1 ** default large
|
||||
# u8x8_font_amstrad_cpc_extended_f, // 2
|
||||
# u8x8_font_5x7_f, // 3
|
||||
# u8x8_font_5x8_f, // 4
|
||||
# u8x8_font_8x13_1x2_f, // 5
|
||||
# u8x8_font_8x13B_1x2_f, // 6
|
||||
# u8x8_font_7x14B_1x2_f, // 7
|
||||
# u8x8_font_artossans8_r, // 8
|
||||
# u8x8_font_artosserif8_r, // 9
|
||||
# u8x8_font_torussansbold8_r, // 10
|
||||
# u8x8_font_victoriabold8_r, // 11
|
||||
# u8x8_font_victoriamedium8_r, // 12
|
||||
# u8x8_font_pressstart2p_f, // 13
|
||||
# u8x8_font_pcsenior_f, // 14
|
||||
# u8x8_font_pxplusibmcgathin_f, // 15
|
||||
# u8x8_font_pxplusibmcga_f, // 16
|
||||
# u8x8_font_pxplustandynewtv_f, // 17
|
||||
#
|
||||
# for ILI9225, these fonts are available:
|
||||
# Terminal6x8 // 0
|
||||
# Terminal11x16 // 1
|
||||
# Terminal12x16 // 2
|
||||
# FreeMono9pt7b, // 3
|
||||
# FreeMono12pt7b, // 4
|
||||
# FreeSans9pt7b, // 5
|
||||
# FreeSans12pt7b, // 6
|
||||
# Picopixel, // 7
|
||||
#
|
||||
# color=rrggbb,rrggbb can be used to select color (foreground, background)
|
||||
# see https://github.com/Nkawu/TFT_22_ILI9225/wiki#color-reference for example (use without "#"-sign)
|
||||
#
|
||||
# for TFT display, coordinates and width are multiplied by xscale,yscale and later used in pixels
|
||||
# with scale=1,1 you can directly use pixel coordinates. (default: xscale=13,yscale=22 => 8 lines, 16 columns)
|
||||
###########
|
||||
|
||||
############
|
||||
# Scan display for large 2" TFT dispaly
|
||||
@ScannerTFT
|
||||
scale=30,18
|
||||
timer=-1,0,0
|
||||
key1action=D,#,F,W
|
||||
key2action=D,#,#,#
|
||||
timeaction=#,D,+
|
||||
fonts=5,6
|
||||
0,0=XScan
|
||||
0,5,-3=S#:
|
||||
0,9,5.5=T
|
||||
3,0=F MHz
|
||||
5,0,16=S
|
||||
7,5=n
|
||||
|
||||
############
|
||||
@MainTFT
|
||||
timer=-1,-1,N
|
||||
key1action=+,0,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,#,0
|
||||
color=FFD700
|
||||
0,0,10.5=Is
|
||||
color=0000FF
|
||||
0,11,-5.5=f
|
||||
1,0,4=t
|
||||
1,10.5,-6=c
|
||||
color=00ff00
|
||||
2,0,7=L
|
||||
4,0,7=O
|
||||
color=FFA500
|
||||
2,9.5,-7=A
|
||||
3,9.5,-7=vm/s
|
||||
color=AA5522
|
||||
4,9.5,-7=hkkm/h
|
||||
color=FFFFFF
|
||||
6,2=r
|
||||
6.3,10=Q4
|
||||
7,0=xd=
|
||||
7,2,6=gD
|
||||
7,12=gI
|
||||
|
||||
############
|
||||
@PeilungTFT
|
||||
timer=-1,-1,N
|
||||
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,N
|
||||
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,-1
|
||||
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
|
||||
|
||||
### Alternative display layouts based on https://gist.github.com/bazjo
|
||||
# Scan display for large 2" TFT dispaly
|
||||
@Scan.TFT.Bazjo
|
||||
timer=-1,0,0
|
||||
key1action=D,#,F,W
|
||||
key2action=D,#,#,#
|
||||
timeaction=#,D,+
|
||||
scale=11,10
|
||||
fonts=0,2
|
||||
color=e0e0e0
|
||||
#Row 1
|
||||
0.5,0=XScanning...
|
||||
#Row 2
|
||||
3,0=xIndex
|
||||
4,0,8=S/
|
||||
3,9=xSite
|
||||
4,9=S
|
||||
#Row 3
|
||||
6,0=xType
|
||||
7,0,6=T
|
||||
6,9=xFrequency
|
||||
7,9=F
|
||||
#Row 4
|
||||
9,0=xWeb UI IP
|
||||
10,0=N
|
||||
#Row 5
|
||||
#Footer
|
||||
color=6C757D
|
||||
15,0=xScan Mode
|
||||
15,18=bVV
|
||||
|
||||
############
|
||||
@Decode/General.TFT.Bazjo
|
||||
timer=-1,-1,N
|
||||
key1action=+,0,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,#,0
|
||||
scale=11,10
|
||||
fonts=0,2
|
||||
#Row 1
|
||||
color=996A06
|
||||
0,0=xSerial
|
||||
0,5=t
|
||||
color=FFB10B
|
||||
1,0=Is
|
||||
color=996A06
|
||||
0,11=xFreq.
|
||||
0,16=c
|
||||
color=FFB10B
|
||||
1,11=F
|
||||
#Row 2
|
||||
color=3C5C99
|
||||
3,0=xLatitude
|
||||
color=639AFF
|
||||
4,0=L
|
||||
color=3C5C99
|
||||
3,11=xLongitude
|
||||
color=639AFF
|
||||
4,11=O
|
||||
#Row 3
|
||||
color=3C5C99
|
||||
6,0=xHoriz. Speed
|
||||
color=639AFF
|
||||
7,0=Hkkm/h
|
||||
color=3C5C99
|
||||
6,11=xVert. Speed
|
||||
color=639AFF
|
||||
7,11=Vm/s
|
||||
#Row 4
|
||||
color=99004A
|
||||
9,0=xAltitude
|
||||
color=FF007B
|
||||
10,0=A
|
||||
color=99004A
|
||||
9,11=xBearing
|
||||
color=FF007B
|
||||
10,11=GB
|
||||
#Row 5
|
||||
color=06998E
|
||||
12,0=xRSSI
|
||||
color=0AFFEF
|
||||
13,0=R
|
||||
color=06998E
|
||||
12,11=xHistory
|
||||
color=0AFFEF
|
||||
13.5,11=Q4
|
||||
#Footer
|
||||
color=6C757D
|
||||
15,0=xDecode Mode / General View
|
||||
15,18=bVV
|
||||
|
||||
############
|
||||
@Decode/Battery.TFT.Bazjo
|
||||
timer=-1,-1,N
|
||||
key1action=+,0,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,#,#
|
||||
scale=11,10
|
||||
fonts=0,2
|
||||
#Row 1
|
||||
color=99001F
|
||||
0,0=xBattery Status
|
||||
0,11=xBattery Voltage
|
||||
color=FF0035
|
||||
1,0=BS
|
||||
1,11=BVV
|
||||
#Row 2
|
||||
color=99001F
|
||||
3,0=xCharge Current
|
||||
3,11=xDischarge Current
|
||||
color=FF0035
|
||||
4,0=BCmA
|
||||
4,11=BDmA
|
||||
#Row 3
|
||||
color=99001F
|
||||
6,0=xUSB Voltage
|
||||
6,11=xUSB Current
|
||||
color=FF0035
|
||||
7,0=BUV
|
||||
7,11=BImA
|
||||
#Row 4
|
||||
color=99001F
|
||||
9,0=xIC Temperature
|
||||
#9,11=xKey
|
||||
color=FF0035
|
||||
10,0=BTC
|
||||
#10,11=XValue
|
||||
#Row 5
|
||||
#12,0=xKey
|
||||
#12,11=xKey
|
||||
#13,0=XValue
|
||||
#13,11=XValue
|
||||
#Footer
|
||||
color=99001F
|
||||
15,0=xDecode Mode/Battery View
|
||||
15,18=bVV
|
||||
|
||||
# based on https://github.com/puspis/rdz_ttgo_sonde
|
||||
##########
|
||||
@Scanner.Puspis
|
||||
timer=-1,0,4
|
||||
key1action=D,#,F,W
|
||||
key2action=D,#,#,#
|
||||
timeaction=#,D,+
|
||||
scale=13,10
|
||||
fonts=0,1
|
||||
#Row 1
|
||||
color=90EE90
|
||||
0.5,3=XFREQUENCY SCAN
|
||||
#Row 2
|
||||
color=00FF00
|
||||
3,0=xMEMORY
|
||||
3,9=xLAUNCH SITE
|
||||
color=639AFF
|
||||
4,0,9=S/
|
||||
4,9=S
|
||||
#Row 3
|
||||
color=00FF00
|
||||
6,0=xTYPE
|
||||
6,9=xFREQUENCY
|
||||
color=639AFF
|
||||
7,0,9=T
|
||||
7,9=F MHz
|
||||
#Row 4
|
||||
fonts=0,5
|
||||
color=285454
|
||||
11.5,0=xIP ADDRESS:
|
||||
10.9,7,-15=N
|
||||
#Footer
|
||||
color=FF0000
|
||||
12.7,18=bVV
|
||||
|
||||
############
|
||||
@Main.Puspis
|
||||
timer=-1,-1,N
|
||||
key1action=+,0,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,#,0
|
||||
scale=11,10
|
||||
fonts=0,2
|
||||
#Row 1
|
||||
color=00FF00
|
||||
0,0=xSONDE ID
|
||||
0,11=xFREQUENCY
|
||||
color=90EE90
|
||||
0,7.4=t
|
||||
1,0=Is
|
||||
1,11=F
|
||||
#Row 2
|
||||
fonts=0,1
|
||||
color=00FF00
|
||||
3,0=xLATITUDE
|
||||
3,11=xLONGITUDE
|
||||
color=FF007B
|
||||
4,0=L
|
||||
4,11=O
|
||||
#Row 3
|
||||
color=00FF00
|
||||
6,0=xWIND SPEED
|
||||
6,11=xCLIMB RATE
|
||||
color=639AFF
|
||||
7,0=Hkkm/h
|
||||
7,11=Vm/s
|
||||
#Row 4
|
||||
color=00FF00
|
||||
9,0=xRX ALTITUDE
|
||||
9,11=xSONDE ALTITUDE
|
||||
color=639AFF
|
||||
10,0=GH
|
||||
10,11=A
|
||||
#Row 5
|
||||
color=00FF00
|
||||
12,0=xDISTANCE
|
||||
12,11=xFRAMES
|
||||
color=FFFFFF
|
||||
13,0=GD
|
||||
13.5,11=Q4
|
||||
#Footer
|
||||
color=FF0000
|
||||
15,0.2=xIP:
|
||||
15,2.5=n
|
||||
15,18=bVV
|
||||
|
||||
############
|
||||
@JotaEme.Puspis
|
||||
timer=-1,-1,N
|
||||
key1action=+,0,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,#,0
|
||||
scale=11,10
|
||||
fonts=0,1
|
||||
#Row 1
|
||||
color=90EE90
|
||||
0,0=Is
|
||||
0.7,10.5=t
|
||||
0,14=F
|
||||
#Row 2
|
||||
color=00FF00
|
||||
2,1.2=xWIND SPEED
|
||||
2,14=xCLIMB RATE
|
||||
color=639AFF
|
||||
3,1=Hkkm/h
|
||||
3,13=Vm/s
|
||||
#Row 3
|
||||
color=00FF00
|
||||
5,1=xRX ALTITUDE
|
||||
5,12.5=xSONDE ALTITUDE
|
||||
color=639AFF
|
||||
6,2=GH
|
||||
6,14=A
|
||||
#Row 4
|
||||
color=00FF00
|
||||
8,0=xSONDE POSITION
|
||||
color=FF007B
|
||||
9,2=l
|
||||
10,2=o
|
||||
#Row 5
|
||||
color=00FF00
|
||||
11.4,2=xDISTANCE
|
||||
color=FFFFFF
|
||||
12.4,1.5=GD
|
||||
#Circle
|
||||
color=EEAA00,000033
|
||||
8,13.8=g0CCS,28,FFFF00,000033,5,9ACD32,5,EEAA00
|
||||
#Footer
|
||||
color=FF0000
|
||||
15,0=n
|
||||
color=FFFFFF,000000
|
||||
15,8.7=Q4
|
||||
color=FF0000
|
||||
15,18.4=bVV
|
||||
|
||||
############
|
||||
@CompassTFT.Puspis
|
||||
timer=-1,-1,N
|
||||
key1action=+,0,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,#,#
|
||||
scale=13,10
|
||||
fonts=0,1
|
||||
#Row 1
|
||||
color=90EE90
|
||||
0.5,1.5=XCOMPASS
|
||||
#Row 2
|
||||
color=00FF00
|
||||
4,2=xRX HEADING
|
||||
color=639AFF
|
||||
5,3.8=GC
|
||||
#Row 3
|
||||
color=00FF00
|
||||
9.5,3=xDISTANCE
|
||||
9.5,13.5=xBEARING
|
||||
color=639AFF
|
||||
10.5,3.4=GD
|
||||
10.5,14.3=GI
|
||||
#Circle
|
||||
color=EEAA00,000033
|
||||
0.2,10=g0CCS,52,FFFF00,000033,10,9ACD32,6,EEAA00
|
||||
#Footer
|
||||
color=FF0000,000000
|
||||
12.7,1=Q4
|
||||
12.7,18=bVV
|
||||
|
||||
############
|
||||
@GPSdataTFT.Puspis
|
||||
timer=-1,-1,N
|
||||
key1action=+,0,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,#,#
|
||||
scale=13,10
|
||||
fonts=0,1
|
||||
#Row 1
|
||||
color=90EE90
|
||||
0.5,0.5=XGPS RECEIVER STATION
|
||||
#Row 2
|
||||
color=00FF00
|
||||
3,0=xRX LATITUDE
|
||||
3,12=xRX LONGITUDE
|
||||
color=639AFF
|
||||
4,0=GA
|
||||
4,12=GO
|
||||
#Row 3
|
||||
color=00FF00
|
||||
6,0=xRX ALTITUDE
|
||||
6,12=xRX HEADING
|
||||
color=639AFF
|
||||
7,0=GH
|
||||
7,12=GC
|
||||
#Row 4
|
||||
color=00FF00
|
||||
9,0=xDISTANCE
|
||||
9,12=xBEARING
|
||||
color=639AFF
|
||||
10,0=GD
|
||||
10,12=GB
|
||||
#Footer
|
||||
color=FF0000,000000
|
||||
12.7,0.4=Q4
|
||||
12.7,18=bVV
|
||||
|
||||
############
|
||||
@BatteryTFT.Puspis
|
||||
timer=-1,-1,-1
|
||||
key1action=+,0,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,#,#
|
||||
scale=13,10
|
||||
fonts=0,1
|
||||
#Row 1
|
||||
color=90EE90
|
||||
0.5,4=XBATTERY STATUS
|
||||
#Row 2
|
||||
color=00FF00
|
||||
3,0=x(C)HARGE/(B)ATT
|
||||
3,11.5=xBATTERY VOLTAGE
|
||||
color=639AFF
|
||||
4,4=BS
|
||||
4,11.5=BVV
|
||||
#Row 3
|
||||
color=00FF00
|
||||
6,0=xCHARGE CURRENT
|
||||
6,11.5=xDISCHG. CURRENT
|
||||
color=639AFF
|
||||
7,0=BCmA
|
||||
7,11.5=BDmA
|
||||
#Row 3
|
||||
color=00FF00
|
||||
9,0=xIC TEMPERATURE
|
||||
9,11.5=xFREQ. OFFSET
|
||||
color=639AFF
|
||||
10,0=BTC
|
||||
10,10=C
|
||||
#Footer
|
||||
color=FF0000,000000
|
||||
12.7,0.4=Q4
|
||||
12.7,18=bVV
|
|
@ -0,0 +1,217 @@
|
|||
## screens3.txt: TFT display (portrait)
|
||||
## based on http://www.p1337.synology.me/dokuwiki/doku.php?id=public:wettersonden
|
||||
# Definition of display content and action behaviour
|
||||
#
|
||||
# Timer: (view timer, rx timer, norx timer)
|
||||
# - value -1: timer is disabled; value>=0: timer fires after (value) seconds
|
||||
# - view timer: time since current view (display mode and sonde) was started
|
||||
# - rx timer: time since when sonde data has been received continuously (trigger immediatly after RX)
|
||||
# - norx timer: time since when no sonde data has been received continuously
|
||||
# (rx and norx timer is started after tuning a new frequency and receiving a signal or not receiving
|
||||
# anything for a 1s period)
|
||||
#
|
||||
# Actions:
|
||||
# - W: activate WiFi scan
|
||||
# - F: activate frequency spectrum display
|
||||
# - 0: activate "Scan:" display (this is basically just display mode 0)
|
||||
# - x: (1..N): activate display mode x [deprecated]
|
||||
# - >: activate next display mode
|
||||
# - D: activate default receiver display (display mode specified in config)
|
||||
# - +: advance to next active sonde from QRG config
|
||||
# - #: no action
|
||||
#
|
||||
# Display content (lower/upper case: small/large font)
|
||||
# line,column=content
|
||||
# for ILI9225 its also possible to indicate
|
||||
# line,column,width=content for text within a box of width 'width'
|
||||
# line,column,-width=content for right-justified text
|
||||
#
|
||||
# XText : Text
|
||||
# F(suffix): frequency (with suffix, e.g., " MHz")
|
||||
# L latitade
|
||||
# O lOngitute
|
||||
# A altitude
|
||||
# Hm(suffix) hor. speed m/s (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
||||
# Hk(suffix) hor. speed km/h (suffix: e.g. "km/h"; no suffix=>km/h as 16x8 bitmap for SSD1306 display only)
|
||||
# V(suffix) vert. speef (suffix: e.g. "m/s"; no suffix=>m/s as 16x8 bitmap for SSD1306 display only)
|
||||
# Ix sonde ID (default/d: dxlaprs; s: short id, n: real serial number)
|
||||
# RS41,RS92: all identical R1234567
|
||||
# DFMx: ID M12345678; short ID and serial 12345678
|
||||
# M10: ID ME95231F0; short ID: M95231F0; serial 9062104592
|
||||
# Q signal quality statistics bar
|
||||
# T type string (RS41/DFM9/DFM6/RS92)
|
||||
# C afC value
|
||||
# N ip address (only tiny font)
|
||||
# S scan list entry info: l/empty: launch site name, #=entry nr, t=total entries, a=active entries, /: #/t
|
||||
# K RS41 kill timer values: Kl launch timer, Kb burst timer, Kc kill countdown
|
||||
# format: K_4: h:mm k_6: h:mm:ss k_s: sssss, nothing shown for other sonde
|
||||
# Mx telemetry value x (t temp p preassure h hyg) [not yet implemented, maybe some day in future]
|
||||
# Gx GPS-related data
|
||||
# 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:
|
||||
# (y should be a 1x2 font (1,5,6,7), x a small font)
|
||||
# u8x8_font_chroma48medium8_r, // 0 ** default small
|
||||
# u8x8_font_7x14_1x2_f, // 1 ** default large
|
||||
# u8x8_font_amstrad_cpc_extended_f, // 2
|
||||
# u8x8_font_5x7_f, // 3
|
||||
# u8x8_font_5x8_f, // 4
|
||||
# u8x8_font_8x13_1x2_f, // 5
|
||||
# u8x8_font_8x13B_1x2_f, // 6
|
||||
# u8x8_font_7x14B_1x2_f, // 7
|
||||
# u8x8_font_artossans8_r, // 8
|
||||
# u8x8_font_artosserif8_r, // 9
|
||||
# u8x8_font_torussansbold8_r, // 10
|
||||
# u8x8_font_victoriabold8_r, // 11
|
||||
# u8x8_font_victoriamedium8_r, // 12
|
||||
# u8x8_font_pressstart2p_f, // 13
|
||||
# u8x8_font_pcsenior_f, // 14
|
||||
# u8x8_font_pxplusibmcgathin_f, // 15
|
||||
# u8x8_font_pxplusibmcga_f, // 16
|
||||
# u8x8_font_pxplustandynewtv_f, // 17
|
||||
#
|
||||
# for ILI9225, these fonts are available:
|
||||
# Terminal6x8 // 0
|
||||
# Terminal11x16 // 1
|
||||
# Terminal12x16 // 2
|
||||
# FreeMono9pt7b, // 3
|
||||
# FreeMono12pt7b, // 4
|
||||
# FreeSans9pt7b, // 5
|
||||
# FreeSans12pt7b, // 6
|
||||
# Picopixel, // 7
|
||||
#
|
||||
# color=rrggbb,rrggbb can be used to select color (foreground, background)
|
||||
# see https://github.com/Nkawu/TFT_22_ILI9225/wiki#color-reference for example (use without "#"-sign)
|
||||
#
|
||||
# for TFT display, coordinates and width are multiplied by xscale,yscale and later used in pixels
|
||||
# with scale=1,1 you can directly use pixel coordinates. (default: xscale=13,yscale=22 => 8 lines, 16 columns)
|
||||
|
||||
###########
|
||||
#
|
||||
# Default configuration for "Scanner" display:
|
||||
# - view timer disabled; rx timer=0; norx timer = 0
|
||||
# => after 1 second immediately an action is triggered
|
||||
# (norx: go to next sonde; rx: go to default receiver display)
|
||||
# - key1 actions: D,0,F,W
|
||||
# => Button press activates default receiver view, double press does nothing
|
||||
# Mid press activates Spectrum display, long press activates Wifi scan
|
||||
# - key2 has no function
|
||||
@ScannerPortrait
|
||||
timer=-1,0,0
|
||||
key1action=D,#,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,D,+
|
||||
0,0=XScan
|
||||
0,5=S#:
|
||||
0,9,4.5=T
|
||||
6,0=XHoehe
|
||||
6,5=GH
|
||||
color=ffff00
|
||||
2,0=F MHz
|
||||
4,0=S
|
||||
color=00ff00,444444
|
||||
7,5=n
|
||||
7,0=bV
|
||||
|
||||
############
|
||||
# Default configuration for "Legacy" display:
|
||||
# - view timer=-1, rx timer=-1 (disabled); norx timer=20 (or -1 for "old" behaviour)
|
||||
# => norx timer fires after not receiving a singla for 20 seconds
|
||||
# - key1 actions: +,0,F,W
|
||||
# => Button1 press: next sonde; double press => @Scanner display
|
||||
# => Mid press activates Spectrum display, long press activates Wifi scan
|
||||
# - key2 actions: 2,#,#,#
|
||||
# => BUtton2 activates display 2 (@Field)
|
||||
# - timer actions: #,#,0
|
||||
# (norx timer: if no signal for >20 seconds: go back to scanner mode)
|
||||
#
|
||||
@LegacyPortrait
|
||||
timer=-1,-1,N
|
||||
key1action=+,0,F,W
|
||||
key2action=>,#,#,#
|
||||
timeaction=#,#,0
|
||||
9,10=f
|
||||
9,0=r
|
||||
9,4=Q
|
||||
5,0=g0NCS,35,ffff00,000044,6,33ff33,5,eeaa00
|
||||
5,7=g0CCS,35,ffff00,000044,6,55ff55,5,eeaa00
|
||||
0,0=s
|
||||
0,9=is
|
||||
2,0=L
|
||||
3,0=O
|
||||
color=FFFF00
|
||||
1,6=Hk km/h
|
||||
color=FF0000
|
||||
1,0=GD
|
||||
color=FFFFFF
|
||||
4,9=GH
|
||||
3,9=V
|
||||
4,0=A
|
||||
|
||||
############
|
||||
@PeilungTFTPortrait
|
||||
timer=-1,-1,N
|
||||
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,35,ffff00,000044,6,33ff33,5,eeaa00
|
||||
1,7=g0CCS,35,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
|
||||
|
||||
############
|
||||
@GPSdataTFTPortrait
|
||||
timer=-1,-1,N
|
||||
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
|
||||
|
||||
############
|
||||
@BatteryTFTPortrait
|
||||
timer=-1,-1,-1
|
||||
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
|
||||
|
|
@ -44,7 +44,7 @@ td#sfreq {
|
|||
outline: none;
|
||||
cursor: pointer;
|
||||
padding: 10px 10px;
|
||||
width: 14vw;
|
||||
width: 12vw;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
|
@ -128,3 +128,129 @@ p{
|
|||
margin: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#map {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.leaflet-popup-content table, .leaflet-popup-content table td {
|
||||
border:0;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.leaflet-popup-content table td:nth-child(2),.leaflet-popup-content table td:nth-child(5) {
|
||||
text-align: right;
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
.leaflet-popup-content table td:nth-child(3),.leaflet-popup-content table td:nth-child(6) {
|
||||
text-align: left;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.leaflet-gps{animation:fading 1s infinite}@keyframes fading{0%{opacity:0.7}50%{opacity:1}100%{opacity:0.7}}
|
||||
|
||||
.leaflet-gps::after {
|
||||
content: '🔵';
|
||||
}
|
||||
.leaflet-gps {
|
||||
margin-left: -7px !important;
|
||||
margin-top: -9px !important;
|
||||
}
|
||||
|
||||
.leaflet-burst::after {
|
||||
content: '💥';
|
||||
}
|
||||
.leaflet-burst {
|
||||
margin-left: -20px !important;
|
||||
margin-top: -22px !important;
|
||||
font-weight: bold;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.leaflet-landing::after {
|
||||
content: '×';
|
||||
}
|
||||
|
||||
.leaflet-landing {
|
||||
margin-left: -13px !important;
|
||||
margin-top: -30px !important;
|
||||
font-weight: bold;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
|
||||
.leaflet-header {
|
||||
text-align: center;
|
||||
width: 250px;
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
.leaflet-header #settings {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.leaflet-header label {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.leaflet-header input {
|
||||
width: 80px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.leaflet-header #submit {
|
||||
margin: 3px auto;
|
||||
}
|
||||
|
||||
.leaflet-footer {
|
||||
display:none;
|
||||
text-align: center;
|
||||
width: 180px;
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.leaflet-center {
|
||||
left:0;
|
||||
right:0;
|
||||
margin: 0 auto;
|
||||
padding: 5px;
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.leaflet-header #sonde_detail {
|
||||
display:none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.leaflet-control-attribution {
|
||||
-moz-transform: rotate(-90deg) translateX(100%);
|
||||
-ms-transform: rotate(-90deg) translateX(100%);
|
||||
-o-transform: rotate(-90deg) translateX(100%);;
|
||||
-webkit-transform: rotate(-90deg) translateX(100%);
|
||||
transform: rotate(-90deg) translateX(100%);
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
-moz-transform-origin: 100% 100%;
|
||||
-ms-transform-origin: 100% 100%;
|
||||
-o-transform-origin: 100% 100%;
|
||||
transform-origin: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.ldot {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ybg { background-color: #E0E000; }
|
||||
.gbg { background-color: green; }
|
||||
.rbg { background-color: red; }
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const char *version_name = "rdzTTGOsonde";
|
||||
const char *version_id = "devel20210728";
|
||||
const char *version_id = "devel20210815";
|
||||
const int SPIFFS_MAJOR=2;
|
||||
const int SPIFFS_MINOR=11;
|
||||
const int SPIFFS_MINOR=14;
|
||||
|
|
|
@ -585,7 +585,7 @@ int DFM::receiveNew() {
|
|||
delay(2);
|
||||
}
|
||||
}
|
||||
return RX_TIMEOUT;
|
||||
return rxframes == 4 ? RX_TIMEOUT : RX_OK;
|
||||
}
|
||||
|
||||
int DFM::receiveOld() {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "../../RX_FSK/features.h"
|
||||
#include <U8x8lib.h>
|
||||
#include <U8g2lib.h>
|
||||
#include <SPIFFS.h>
|
||||
|
@ -24,9 +25,16 @@ extern AXP20X_Class axp;
|
|||
extern bool axp192_found;
|
||||
extern SemaphoreHandle_t axpSemaphore;
|
||||
|
||||
extern xSemaphoreHandle globalLock;
|
||||
#define SPI_MUTEX_LOCK() \
|
||||
do \
|
||||
{ \
|
||||
} while (xSemaphoreTake(globalLock, portMAX_DELAY) != pdPASS)
|
||||
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(globalLock)
|
||||
|
||||
struct GpsPos gpsPos;
|
||||
|
||||
SPIClass spiDisp(HSPI);
|
||||
//SPIClass spiDisp(HSPI);
|
||||
|
||||
const char *sondeTypeStr[NSondeTypes] = { "DFM ", "DFM9", "RS41", "RS92", "M10 ", "M20 ", "DFM6", "MP3H" };
|
||||
const char *sondeTypeLongStr[NSondeTypes] = { "DFM (all)", "DFM9 (old)", "RS41", "RS92", "M10 ", "M20 ", "DFM6 (old)", "MP3-H1" };
|
||||
|
@ -312,14 +320,8 @@ void U8x8Display::drawQS(uint8_t x, uint8_t y, uint8_t len, uint8_t /*size*/, ui
|
|||
|
||||
|
||||
const GFXfont *gfl[] = {
|
||||
#ifdef ALT9225
|
||||
&Terminal11x16Font, // 3 (replacement for 1 or 2 with old library)
|
||||
&Terminal11x16Font, // 4 (replacement for 1 or 2 with old library)
|
||||
#else
|
||||
// nobody was using them, so removed with new library
|
||||
&FreeMono9pt7b, // 3
|
||||
&FreeMono12pt7b, // 4
|
||||
#endif
|
||||
&FreeSans9pt7b, // 5
|
||||
&FreeSans12pt7b, // 6
|
||||
&Picopixel, // 7
|
||||
|
@ -331,13 +333,8 @@ struct gfxoffset_t {
|
|||
// first value: offset: max offset from font glyphs (last column * (-1)) (check /, \, `, $)`
|
||||
// yclear:max height: max of (height in 3rd column) + (yofs + 6th column) (check j)
|
||||
const struct gfxoffset_t gfxoffsets[]={
|
||||
#ifdef ALT9225
|
||||
{ 16, 18},
|
||||
{ 16, 18},
|
||||
#else
|
||||
{ 11, 15 }, // 13+11-9 "j"
|
||||
{ 15, 20 }, // 19+15-14
|
||||
#endif
|
||||
{ 13, 18 }, // 17+13-12 "j"
|
||||
{ 17, 23 }, // 23+17-17
|
||||
{ 4, 6}, // 6+4-4
|
||||
|
@ -348,55 +345,49 @@ static int ngfx = sizeof(gfl)/sizeof(GFXfont *);
|
|||
#define TFT_LED 0 // 0 if wired to +5V directly
|
||||
#define TFT_BRIGHTNESS 100 // Initial brightness of TFT backlight (optional)
|
||||
|
||||
#ifdef ALT9225
|
||||
Arduino_DataBus *bus;
|
||||
#endif
|
||||
|
||||
|
||||
void ILI9225Display::begin() {
|
||||
#ifdef ALT9225
|
||||
Serial.println("ILI9225 init (alt driver)");
|
||||
bus = new Arduino_ESP32SPI( sonde.config.tft_rs, sonde.config.tft_cs,
|
||||
sonde.config.oled_scl, sonde.config.oled_sda, -1, HSPI);
|
||||
tft = new Arduino_ILI9225(bus, sonde.config.oled_rst);
|
||||
Serial.println("ILI9225 init (alt driver): done");
|
||||
tft->begin();
|
||||
Serial.println("ILI9225/ILI9341 init");
|
||||
// On the M5, the display and the Lora chip are on the same SPI interface (VSPI default pins),
|
||||
// we must use the same SPI bus with correct locking
|
||||
if(sonde.config.type == TYPE_M5_CORE2) {
|
||||
bus = new Arduino_ESP32SPI( sonde.config.tft_rs, sonde.config.tft_cs,
|
||||
sonde.config.oled_scl, sonde.config.oled_sda, 38, VSPI);
|
||||
} else {
|
||||
bus = new Arduino_ESP32SPI( sonde.config.tft_rs, sonde.config.tft_cs,
|
||||
sonde.config.oled_scl, sonde.config.oled_sda, -1, HSPI);
|
||||
}
|
||||
if(_type == 3)
|
||||
tft = new Arduino_ILI9341(bus, sonde.config.oled_rst);
|
||||
else if(_type == 4)
|
||||
tft = new Arduino_ILI9342(bus, sonde.config.oled_rst);
|
||||
else
|
||||
tft = new Arduino_ILI9225(bus, sonde.config.oled_rst);
|
||||
Serial.println("ILI9225/ILI9341 init: done");
|
||||
tft->begin(sonde.config.tft_spifreq);
|
||||
tft->fillScreen(BLACK);
|
||||
tft->setRotation(sonde.config.tft_orient);
|
||||
tft->setTextWrap(false);
|
||||
#else
|
||||
tft = new MY_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->setModeFlip(sonde.config.tft_modeflip);
|
||||
tft->begin(spiDisp);
|
||||
tft->setOrientation(sonde.config.tft_orient);
|
||||
#endif
|
||||
if(sonde.config.type == TYPE_M5_CORE2)
|
||||
tft->invertDisplay(true);
|
||||
}
|
||||
|
||||
void ILI9225Display::clear() {
|
||||
#ifdef ALT9225
|
||||
tft->fillScreen(0);
|
||||
#else
|
||||
tft->clear();
|
||||
#endif
|
||||
SPI_MUTEX_LOCK();
|
||||
tft->fillScreen(BLACK);
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
// for now, 0=small=FreeSans9pt7b, 1=large=FreeSans18pt7b
|
||||
void ILI9225Display::setFont(uint8_t fontindex) {
|
||||
#ifdef ALT9225
|
||||
if(fontindex==1 || fontindex==2) { fontindex=3; }
|
||||
#endif
|
||||
findex = fontindex;
|
||||
switch(fontindex) {
|
||||
#ifdef ALT9225
|
||||
case 0: tft->setFont(NULL); tft->setTextSize(1); break;
|
||||
case 1: tft->setFont(NULL); tft->setTextSize(2); break;
|
||||
case 2: tft->setFont(NULL); tft->setTextSize(2); break;
|
||||
default: tft->setFont(gfl[fontindex-3]);
|
||||
#else
|
||||
case 0: tft->setFont(Terminal6x8); break;
|
||||
case 1: tft->setFont(Terminal11x16); break;
|
||||
case 2: tft->setFont(Terminal12x16); break;
|
||||
default: tft->setGFXFont(gfl[fontindex-3]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,7 +409,6 @@ void ILI9225Display::getDispSize(uint8_t *height, uint8_t *width, uint8_t *lines
|
|||
break;
|
||||
default: // get size from GFX Font
|
||||
{
|
||||
#ifdef ALT9225
|
||||
int16_t x, y;
|
||||
uint16_t w, h;
|
||||
tft->getTextBounds("|", 0, 0, &x, &y, &w, &h);
|
||||
|
@ -426,13 +416,6 @@ void ILI9225Display::getDispSize(uint8_t *height, uint8_t *width, uint8_t *lines
|
|||
tft->getTextBounds("A", 0, 0, &x, &y, &w, &h);
|
||||
if(colskip) *colskip = w+2;
|
||||
if(lineskip&&colskip) { Serial.printf("skip size from bounds: %d, %d\n", *lineskip, *colskip); }
|
||||
#else
|
||||
int16_t w,h,a;
|
||||
tft->getGFXCharExtent('|',&w,&h,&a);
|
||||
if(lineskip) *lineskip = h+2;
|
||||
tft->getGFXCharExtent('A',&w,&h,&a);
|
||||
if(colskip) *colskip = w+2; // just an approximation
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -448,16 +431,12 @@ void ILI9225Display::drawString(uint8_t x, uint8_t y, const char *s, int16_t wid
|
|||
}
|
||||
// Standard font
|
||||
if(findex<3) {
|
||||
SPI_MUTEX_LOCK();
|
||||
DebugPrintf(DEBUG_DISPLAY, "Simple Text %s at %d,%d [%d]\n", s, x, y, width);
|
||||
#ifdef ALT9225
|
||||
// for gpx fonts and new library, cursor is at baseline!!
|
||||
int h = 6; if(findex>1) h=12;
|
||||
#else
|
||||
tft->setBackgroundColor(bg);
|
||||
int h = tft->getFont().height;
|
||||
#endif
|
||||
if( alignright ) {
|
||||
#ifdef ALT9225
|
||||
#if 1
|
||||
//w = tft->getTextWidth(s);
|
||||
/// TODO
|
||||
if( width==WIDTH_AUTO ) { width = w; }
|
||||
|
@ -476,7 +455,6 @@ void ILI9225Display::drawString(uint8_t x, uint8_t y, const char *s, int16_t wid
|
|||
tft->drawText(x + width - w, y, s, fg);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef ALT9225
|
||||
tft->setCursor(x, y);
|
||||
tft->setTextColor(fg, bg);
|
||||
tft->print(s);
|
||||
|
@ -486,25 +464,16 @@ void ILI9225Display::drawString(uint8_t x, uint8_t y, const char *s, int16_t wid
|
|||
//if(curx < x + width) {
|
||||
// tft->fillRectangle(curx, y, x + width - 1, y + h - 1, bg);
|
||||
//}
|
||||
#else
|
||||
int curx = tft->drawText(x, y, s, fg);
|
||||
if( width==WIDTH_AUTO ) { return; }
|
||||
if(curx < x + width) {
|
||||
tft->fillRectangle(curx, y, x + width - 1, y + h - 1, bg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
SPI_MUTEX_UNLOCK();
|
||||
return;
|
||||
}
|
||||
// GFX font
|
||||
SPI_MUTEX_LOCK();
|
||||
int16_t x1, y1;
|
||||
if(1||width==WIDTH_AUTO || alignright) {
|
||||
#ifdef ALT9225
|
||||
tft->getTextBounds(s, x, y + gfxoffsets[findex-3].yofs, &x1, &y1, (uint16_t *)&w, (uint16_t *)&h);
|
||||
w += x1 - x + 1;
|
||||
#else
|
||||
tft->getGFXTextExtent(s, x, y + gfxoffsets[findex-3].yofs, &w, &h);
|
||||
#endif
|
||||
if(width==WIDTH_AUTO) { width=w; }
|
||||
if(alignright) {
|
||||
if(w > width) {
|
||||
|
@ -530,7 +499,7 @@ void ILI9225Display::drawString(uint8_t x, uint8_t y, const char *s, int16_t wid
|
|||
}
|
||||
#else
|
||||
// Text by drawing bitmap.... => less "flicker"
|
||||
#ifdef ALT9225
|
||||
#if 1
|
||||
//TODO
|
||||
tft->setCursor( alignright? x+width-w : x, y + gfxoffsets[findex-3].yofs);
|
||||
tft->setTextColor( fg, bg );
|
||||
|
@ -568,11 +537,12 @@ void ILI9225Display::drawString(uint8_t x, uint8_t y, const char *s, int16_t wid
|
|||
free(bitmap);
|
||||
#endif
|
||||
#endif
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void ILI9225Display::drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr) {
|
||||
#ifdef ALT9225
|
||||
int i,j;
|
||||
SPI_MUTEX_LOCK();
|
||||
tft->startWrite();
|
||||
for(i=0; i<cnt*8; i++) {
|
||||
uint8_t v = tile_ptr[i];
|
||||
|
@ -582,9 +552,7 @@ void ILI9225Display::drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_p
|
|||
}
|
||||
}
|
||||
tft->endWrite();
|
||||
#else
|
||||
tft->drawTile(x, y, cnt, tile_ptr);
|
||||
#endif
|
||||
SPI_MUTEX_UNLOCK();
|
||||
#if 0
|
||||
int i,j;
|
||||
tft->startWrite();
|
||||
|
@ -602,26 +570,24 @@ void ILI9225Display::drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_p
|
|||
}
|
||||
|
||||
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) {
|
||||
SPI_MUTEX_LOCK();
|
||||
if(fill)
|
||||
tft->fillTriangle(x1, y1, x2, y2, x3, y3, color);
|
||||
else
|
||||
tft->drawTriangle(x1, y1, x2, y2, x3, y3, color);
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void ILI9225Display::drawBitmap(uint16_t x1, uint16_t y1, const uint16_t* bitmap, int16_t w, int16_t h) {
|
||||
#ifdef ALT9225
|
||||
SPI_MUTEX_LOCK();
|
||||
tft->draw16bitRGBBitmap(x1, y1, bitmap, w, h);
|
||||
#else
|
||||
tft->drawBitmap(x1, y1, bitmap, w, h);
|
||||
#endif
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void ILI9225Display::welcome() {
|
||||
#ifdef ALT9225
|
||||
SPI_MUTEX_LOCK();
|
||||
tft->fillScreen(0);
|
||||
#else
|
||||
tft->clear();
|
||||
#endif
|
||||
SPI_MUTEX_UNLOCK();
|
||||
setFont(6);
|
||||
drawString(0, 0*22, version_name, WIDTH_AUTO, 0xff00);
|
||||
setFont(5);
|
||||
|
@ -669,8 +635,9 @@ void ILI9225Display::drawQS(uint8_t x, uint8_t y, uint8_t len, uint8_t size, uin
|
|||
#define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
|
||||
|
||||
|
||||
#ifdef ALT9225
|
||||
#if 1
|
||||
#else
|
||||
// TO BE REMOVED
|
||||
void MY_ILI9225::drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr) {
|
||||
int i,j;
|
||||
startWrite();
|
||||
|
@ -731,8 +698,8 @@ RawDisplay *Display::rdis = NULL;
|
|||
//TODO: maybe merge with initFromFile later?
|
||||
void Display::init() {
|
||||
Serial.printf("disptype is %d\n",sonde.config.disptype);
|
||||
if(sonde.config.disptype==1) {
|
||||
rdis = new ILI9225Display();
|
||||
if(sonde.config.disptype==1 || sonde.config.disptype==3 || sonde.config.disptype==4 ) {
|
||||
rdis = new ILI9225Display(sonde.config.disptype);
|
||||
} else {
|
||||
rdis = new U8x8Display(sonde.config.disptype);
|
||||
}
|
||||
|
@ -972,17 +939,33 @@ int Display::countEntries(File f) {
|
|||
return n;
|
||||
}
|
||||
|
||||
int Display::getScreenIndex(int index) {
|
||||
if(index!=0) return index;
|
||||
switch(sonde.config.disptype) {
|
||||
case 1: // ILI9225
|
||||
index = 2; // landscape mode (orient=1/3)
|
||||
if( (sonde.config.tft_orient&0x01)==0 ) index++; // portrait mode (0/2)
|
||||
break;
|
||||
case 3: // ILI9341
|
||||
case 4: // ILI9342
|
||||
index = 4; // landscape mode (orient=1/3)
|
||||
if( (sonde.config.tft_orient&0x01)==0 ) index++; // portrait mode (0/2)
|
||||
break;
|
||||
case 0: case 2: // small OLED display (SD1306/SH1106)
|
||||
default:
|
||||
index = 1; break;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
void Display::initFromFile(int index) {
|
||||
File d;
|
||||
if(index>0) {
|
||||
char file[20];
|
||||
snprintf(file, 20, "/screens%d.txt", index);
|
||||
Serial.printf("Reading %s\n", file);
|
||||
d = SPIFFS.open(file, "r");
|
||||
if(!d || d.available()==0 ) { Serial.printf("%s not found, using /screens.txt\n", file); }
|
||||
}
|
||||
if(!d || d.available()==0 ) d = SPIFFS.open("/screens.txt", "r");
|
||||
if(!d) return;
|
||||
char file[20];
|
||||
|
||||
index = getScreenIndex(index); // auto selection for index==0
|
||||
snprintf(file, 20, "/screens%d.txt", index);
|
||||
Serial.printf("Reading %s\n", file);
|
||||
d = SPIFFS.open(file, "r");
|
||||
if(!d || d.available()==0 ) { Serial.printf("%s not found\n", file); return; }
|
||||
|
||||
DispInfo *newlayouts = (DispInfo *)malloc(MAXSCREENS * sizeof(DispInfo));
|
||||
if(!newlayouts) {
|
||||
|
@ -1086,7 +1069,7 @@ void Display::initFromFile(int index) {
|
|||
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; }
|
||||
if(sonde.config.disptype==1 || sonde.config.disptype==3 || sonde.config.disptype==4 ) { 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;
|
||||
|
@ -1244,6 +1227,7 @@ void Display::drawID(DispEntry *de) {
|
|||
}
|
||||
void Display::drawRSSI(DispEntry *de) {
|
||||
rdis->setFont(de->fmt);
|
||||
// TODO.... 3/4!!!!!
|
||||
if(sonde.config.disptype!=1) {
|
||||
snprintf(buf, 16, "-%d ", sonde.si()->rssi/2);
|
||||
int len=strlen(buf)-3;
|
||||
|
@ -1275,10 +1259,7 @@ void Display::drawFreq(DispEntry *de) {
|
|||
drawString(de, buf);
|
||||
}
|
||||
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); }
|
||||
drawString(de, buf+strlen(buf)-8);
|
||||
}
|
||||
|
@ -1291,7 +1272,7 @@ void Display::drawSite(DispEntry *de) {
|
|||
switch(de->extra[0]) {
|
||||
case '#':
|
||||
// currentSonde is index in array starting with 0;
|
||||
// but we draw "1" for the first entrie and so on...
|
||||
// but we draw "1" for the first entry and so on...
|
||||
snprintf(buf, 3, "%2d", sonde.currentSonde+1);
|
||||
buf[2]=0;
|
||||
break;
|
||||
|
@ -1361,6 +1342,15 @@ void Display::drawKilltimer(DispEntry *de) {
|
|||
#define FAKEGPS 0
|
||||
|
||||
extern int lastCourse; // from RX_FSK.ino
|
||||
|
||||
|
||||
float calcLatLonDist(float lat1, float lon1, float lat2, float lon2) {
|
||||
float x = radians(lon1-lon2) * cos( radians((lat1+lat2)/2) );
|
||||
float y = radians(lat2-lat1);
|
||||
float d = sqrt(x*x+y*y)*EARTH_RADIUS;
|
||||
return d;
|
||||
}
|
||||
|
||||
void Display::calcGPS() {
|
||||
// base data
|
||||
#if 0
|
||||
|
@ -1392,12 +1382,7 @@ static int tmpc=0;
|
|||
#endif
|
||||
// distance
|
||||
if( gpsPos.valid && (sonde.si()->validPos&0x03)==0x03 && (layout->usegps&GPSUSE_DIST)) {
|
||||
float lat1 = gpsPos.lat;
|
||||
float lat2 = sonde.si()->lat;
|
||||
float x = radians(gpsPos.lon-sonde.si()->lon) * cos( radians((lat1+lat2)/2) );
|
||||
float y = radians(lat2-lat1);
|
||||
float d = sqrt(x*x+y*y)*EARTH_RADIUS;
|
||||
gpsDist = (int)d;
|
||||
gpsDist = (int)calcLatLonDist(gpsPos.lat, gpsPos.lon, sonde.si()->lat, sonde.si()->lon);
|
||||
} else {
|
||||
gpsDist = -1;
|
||||
}
|
||||
|
@ -1538,7 +1523,8 @@ void Display::drawGPS(DispEntry *de) {
|
|||
}
|
||||
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
|
||||
#ifdef ALT9225
|
||||
#if 1
|
||||
// TODO
|
||||
#else
|
||||
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, size);
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#define ALT9225
|
||||
|
||||
#ifndef Display_h
|
||||
#define Display_h
|
||||
|
||||
|
@ -7,11 +5,7 @@
|
|||
#define FONT_SMALL 0
|
||||
|
||||
#include <SPI.h>
|
||||
#ifdef ALT9225
|
||||
#include <Arduino_GFX_Library.h>
|
||||
#else
|
||||
#include <TFT22_ILI9225.h>
|
||||
#endif
|
||||
#include <U8x8lib.h>
|
||||
#include <SPIFFS.h>
|
||||
|
||||
|
@ -81,12 +75,12 @@ public:
|
|||
class U8x8Display : public RawDisplay {
|
||||
private:
|
||||
U8X8 *u8x8 = NULL; // initialize later after reading config file
|
||||
int _type;
|
||||
uint8_t _type;
|
||||
const uint8_t **fontlist;
|
||||
int nfonts;
|
||||
|
||||
public:
|
||||
U8x8Display(int type = 0) { _type = type; }
|
||||
U8x8Display(uint8_t type = 0) { _type = type; }
|
||||
void begin();
|
||||
void clear();
|
||||
void setFont(uint8_t fontindex);
|
||||
|
@ -100,24 +94,17 @@ public:
|
|||
void drawQS(uint8_t x, uint8_t y, uint8_t len, uint8_t size, uint8_t *stat, uint16_t fg=0xffff, uint16_t bg=0);
|
||||
};
|
||||
|
||||
#ifdef ALT9225
|
||||
typedef Arduino_GFX MY_ILI9225;
|
||||
#else
|
||||
class MY_ILI9225 : public TFT22_ILI9225 {
|
||||
using TFT22_ILI9225::TFT22_ILI9225;
|
||||
public:
|
||||
uint16_t drawGFXChar(int16_t x, int16_t y, unsigned char c, uint16_t color);
|
||||
void drawTile(uint8_t x, uint8_t y, uint8_t cnt, uint8_t *tile_ptr);
|
||||
};
|
||||
#endif
|
||||
typedef Arduino_GFX MY_ILI9225;
|
||||
|
||||
class ILI9225Display : public RawDisplay {
|
||||
private:
|
||||
uint8_t yofs=0;
|
||||
uint8_t findex=0;
|
||||
uint8_t _type;
|
||||
|
||||
public:
|
||||
MY_ILI9225 *tft = NULL; // initialize later after reading config file
|
||||
ILI9225Display(int type = 1) { _type = type; }
|
||||
void begin();
|
||||
void clear();
|
||||
void setFont(uint8_t fontindex);
|
||||
|
@ -161,6 +148,7 @@ private:
|
|||
return ret;
|
||||
}
|
||||
public:
|
||||
static int getScreenIndex(int index);
|
||||
void initFromFile(int index);
|
||||
|
||||
int layoutIdx;
|
||||
|
|
|
@ -276,6 +276,7 @@ int M10M20::decodeframeM10(uint8_t *data) {
|
|||
}
|
||||
Serial.println(crcok?"CRC OK":"CRC NOT OK");
|
||||
Serial.printf(" repair: %d/%d\n", repl, repairstep);
|
||||
if(!crcok) return 2;
|
||||
|
||||
if(data[1]==0x9F && data[2]==0x20) {
|
||||
Serial.println("Decoding...");
|
||||
|
@ -338,7 +339,7 @@ int M10M20::decodeframeM10(uint8_t *data) {
|
|||
Serial.printf("data is %02x %02x %02x\n", data[0], data[1], data[2]);
|
||||
return 0;
|
||||
}
|
||||
return crcok?1:2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t rxdata;
|
||||
|
@ -392,12 +393,14 @@ void M10M20::processM10data(uint8_t dt)
|
|||
if(rxp==2 && dataptr[0]==0x45 && dataptr[1]==0x20) { isM20 = true; }
|
||||
if(isM20) {
|
||||
memcpy(sonde.si()->typestr, "M20 ", 5);
|
||||
sonde.si()->subtype = 2;
|
||||
if(rxp>=M20_FRAMELEN) {
|
||||
rxsearching = true;
|
||||
haveNewFrame = decodeframeM20(dataptr);
|
||||
}
|
||||
} else {
|
||||
memcpy(sonde.si()->typestr, "M10 ", 5);
|
||||
sonde.si()->subtype = 1;
|
||||
if(rxp>=M10_FRAMELEN) {
|
||||
rxsearching = true;
|
||||
haveNewFrame = decodeframeM10(dataptr);
|
||||
|
|
|
@ -14,13 +14,38 @@
|
|||
#include <Sonde.h>
|
||||
#include <Display.h>
|
||||
|
||||
SX1278FSK::SX1278FSK()
|
||||
|
||||
#define SPI_MUTEX_LOCK() \
|
||||
do \
|
||||
{ \
|
||||
} while (xSemaphoreTake(_lock, portMAX_DELAY) != pdPASS)
|
||||
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(_lock)
|
||||
|
||||
SX1278FSK::SX1278FSK() {}
|
||||
|
||||
void SX1278FSK::setup(xSemaphoreHandle lock)
|
||||
{
|
||||
// Initialize class variables
|
||||
_lock = lock;
|
||||
Serial.println("Setup sx1278");
|
||||
if(_lock) SPI_MUTEX_LOCK();
|
||||
digitalWrite(sonde.config.sx1278_ss, HIGH);
|
||||
pinMode(sonde.config.sx1278_ss, OUTPUT);
|
||||
Serial.printf("Configuing SX1278FSK SPI with miso=%d, mosi=%d, sck=%d, ss=%d\n", sonde.config.sx1278_miso,
|
||||
sonde.config.sx1278_mosi, sonde.config.sx1278_sck, sonde.config.sx1278_ss);
|
||||
SPI.begin(sonde.config.sx1278_sck, sonde.config.sx1278_miso, sonde.config.sx1278_mosi, -1); // no hardware CS
|
||||
// was: SPI.begin();
|
||||
|
||||
//Set most significant bit first
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
//Divide the clock frequency
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
//Set data mode
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
if(_lock) SPI_MUTEX_UNLOCK();
|
||||
};
|
||||
|
||||
|
||||
static SPISettings spiset = SPISettings(40000000L, MSBFIRST, SPI_MODE0);
|
||||
static SPISettings spiset = SPISettings(10000000L, MSBFIRST, SPI_MODE0);
|
||||
|
||||
/*
|
||||
Function: Turns the module ON.
|
||||
|
@ -34,19 +59,6 @@ uint8_t SX1278FSK::ON()
|
|||
Serial.println(F("Starting 'ON'"));
|
||||
#endif
|
||||
|
||||
// Powering the module
|
||||
pinMode(SX1278_SS, OUTPUT);
|
||||
digitalWrite(SX1278_SS, HIGH);
|
||||
|
||||
//Configure the MISO, MOSI, CS, SPCR.
|
||||
SPI.begin();
|
||||
//Set most significant bit first
|
||||
SPI.setBitOrder(MSBFIRST);
|
||||
//Divide the clock frequency
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
//Set data mode
|
||||
SPI.setDataMode(SPI_MODE0);
|
||||
|
||||
// Set Maximum Over Current Protection
|
||||
state = setMaxCurrent(0x1B);
|
||||
if( state == 0 )
|
||||
|
@ -60,7 +72,6 @@ uint8_t SX1278FSK::ON()
|
|||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// set FSK mode
|
||||
state = setFSK();
|
||||
return state;
|
||||
|
@ -77,10 +88,12 @@ void SX1278FSK::OFF()
|
|||
Serial.println(F("Starting 'OFF'"));
|
||||
#endif
|
||||
|
||||
SPI.end();
|
||||
//SPI.end();
|
||||
#if 0
|
||||
// Powering the module
|
||||
pinMode(SX1278_SS,OUTPUT);
|
||||
digitalWrite(SX1278_SS,LOW);
|
||||
#endif
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.println(F("## Setting OFF ##"));
|
||||
|
@ -98,15 +111,16 @@ byte SX1278FSK::readRegister(byte address)
|
|||
{
|
||||
byte value = 0x00;
|
||||
|
||||
if(_lock) SPI_MUTEX_LOCK();
|
||||
digitalWrite(sonde.config.sx1278_ss,LOW);
|
||||
SPI.beginTransaction(spiset);
|
||||
digitalWrite(SX1278_SS,LOW);
|
||||
|
||||
//delay(1);
|
||||
bitClear(address, 7); // Bit 7 cleared to write in registers
|
||||
SPI.transfer(address);
|
||||
value = SPI.transfer(0x00);
|
||||
digitalWrite(SX1278_SS,HIGH);
|
||||
SPI.endTransaction();
|
||||
digitalWrite(sonde.config.sx1278_ss,HIGH);
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
if(address!=0x3F) {
|
||||
|
@ -118,7 +132,7 @@ byte SX1278FSK::readRegister(byte address)
|
|||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
if(_lock) SPI_MUTEX_UNLOCK();
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -131,15 +145,16 @@ Parameters:
|
|||
*/
|
||||
void SX1278FSK::writeRegister(byte address, byte data)
|
||||
{
|
||||
if(_lock) SPI_MUTEX_LOCK();
|
||||
digitalWrite(sonde.config.sx1278_ss,LOW);
|
||||
SPI.beginTransaction(spiset);
|
||||
digitalWrite(SX1278_SS,LOW);
|
||||
|
||||
//delay(1);
|
||||
bitSet(address, 7); // Bit 7 set to read from registers
|
||||
SPI.transfer(address);
|
||||
SPI.transfer(data);
|
||||
digitalWrite(SX1278_SS,HIGH);
|
||||
SPI.endTransaction();
|
||||
digitalWrite(sonde.config.sx1278_ss,HIGH);
|
||||
|
||||
#if (SX1278FSK_debug_mode > 1)
|
||||
Serial.print(F("## Writing: ##\t"));
|
||||
|
@ -150,7 +165,7 @@ void SX1278FSK::writeRegister(byte address, byte data)
|
|||
Serial.print(data, HEX);
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if(_lock) SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -867,4 +882,5 @@ void SX1278FSK::showRxRegisters()
|
|||
}
|
||||
#endif
|
||||
|
||||
xSemaphoreHandle globalLock =xSemaphoreCreateMutex();
|
||||
SX1278FSK sx1278 = SX1278FSK();
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
|
||||
#define SX1278FSK_debug_mode 0
|
||||
|
||||
#define SX1278_SS SS
|
||||
|
||||
//! MACROS //
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01) // read a bit
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit))) // set bit to '1'
|
||||
|
@ -171,7 +169,9 @@ class SX1278FSK
|
|||
{
|
||||
public:
|
||||
// class constructor
|
||||
SX1278FSK();
|
||||
SX1278FSK();
|
||||
|
||||
void setup(xSemaphoreHandle lock);
|
||||
|
||||
// Turn on SX1278 module (return 0 on sucess, 1 otherwise)
|
||||
uint8_t ON();
|
||||
|
@ -256,7 +256,7 @@ public:
|
|||
// Receive a packet
|
||||
uint8_t receivePacketTimeout(uint32_t wait, byte *data);
|
||||
|
||||
|
||||
xSemaphoreHandle _lock = NULL;
|
||||
|
||||
#if 0
|
||||
//! It gets the internal temperature of the module.
|
||||
|
|
|
@ -24,6 +24,7 @@ struct scancfg {
|
|||
//struct scancfg scanLCD={ 121, 7, 120/6, 120/6/4, 6000.0/120.0/20.0, 20, 120*20, 1 };
|
||||
struct scancfg scanLCD={ 121, 7, 120/6, 120/6/4, 6000.0/120.0/10.0, 10, 120*10, 2, 40 };
|
||||
struct scancfg scanTFT={ 210, 16, 210/6, 210/6/5, 6000.0/210.0/10.0, 10, 210*10, 1, 0 };
|
||||
struct scancfg scan9341={ 210, 16, 210/6, 210/6/5, 6000.0/210.0/10.0, 10, 210*10, 1, 0 };
|
||||
|
||||
struct scancfg &scanconfig = scanTFT;
|
||||
|
||||
|
@ -65,7 +66,7 @@ void Scanner::fillTiles(uint8_t *row, int value) {
|
|||
///// unused???? uint8_t tiles[16] = { 0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0, 1, 3, 7, 15, 31, 63, 127, 255};
|
||||
|
||||
// type 0: lcd, 1: tft, 2: lcd(sh1106)
|
||||
#define ISTFT (sonde.config.disptype==1)
|
||||
#define ISTFT (sonde.config.disptype==1 || sonde.config.disptype==3)
|
||||
void Scanner::plotResult()
|
||||
{
|
||||
int yofs = 0;
|
||||
|
|
|
@ -82,16 +82,21 @@ void Sonde::defaultConfig() {
|
|||
config.power_pout = -1;
|
||||
config.spectrum=10;
|
||||
// Try autodetecting board type
|
||||
config.type = TYPE_TTGO;
|
||||
// Seems like on startup, GPIO4 is 1 on v1 boards, 0 on v2.1 boards?
|
||||
config.gps_rxd = -1;
|
||||
config.gps_txd = -1;
|
||||
config.sx1278_ss = SS; // default SS pin, on all TTGOs
|
||||
config.sx1278_miso = MISO;
|
||||
config.sx1278_mosi = MOSI;
|
||||
config.sx1278_sck = SCK;
|
||||
config.oled_rst = 16;
|
||||
config.disptype = 0;
|
||||
config.tft_orient = 1;
|
||||
config.button2_axp = 0;
|
||||
config.norx_timeout = 20;
|
||||
config.screenfile = 1;
|
||||
config.tft_modeflip = 0;
|
||||
config.tft_spifreq = SPI_DEFAULT_FREQ;
|
||||
if(initlevels[16]==0) {
|
||||
config.oled_sda = 4;
|
||||
config.oled_scl = 15;
|
||||
|
@ -103,32 +108,55 @@ void Sonde::defaultConfig() {
|
|||
} else {
|
||||
config.oled_sda = 21;
|
||||
config.oled_scl = 22;
|
||||
if(initlevels[17]==0) { // T-Beam
|
||||
if(initlevels[17]==0) { // T-Beam or M5Stack Core2?
|
||||
int tbeam=7;
|
||||
if(initlevels[12]==0) {
|
||||
tbeam = 10;
|
||||
Serial.println("Autoconfig: looks like T-Beam 1.0 board");
|
||||
Serial.println("Autoconfig: looks like T-Beam 1.0 or M5Stack Core2 board");
|
||||
} else if ( initlevels[4]==1 && initlevels[12]==1 ) {
|
||||
tbeam = 11;
|
||||
Serial.println("Autoconfig: looks like T-Beam 1.1 board");
|
||||
}
|
||||
if(tbeam == 10 || tbeam == 11) { // T-Beam v1.0 or T-Beam v1.1
|
||||
config.button_pin = 38;
|
||||
config.button2_pin = 15 + 128; //T4 + 128; // T4 = GPIO13
|
||||
// Maybe in future use as default only PWR as button2?
|
||||
//config.button2_pin = 255;
|
||||
config.button2_axp = 1;
|
||||
config.gps_rxd = 34;
|
||||
config.gps_txd = 12;
|
||||
// Check for I2C-Display@21,22
|
||||
#define SSD1306_ADDRESS 0x3c
|
||||
Wire.begin(21, 22);
|
||||
Wire.beginTransmission(SSD1306_ADDRESS);
|
||||
byte err = Wire.endTransmission();
|
||||
delay(100); // otherwise its too fast?!
|
||||
Wire.beginTransmission(SSD1306_ADDRESS);
|
||||
err = Wire.endTransmission();
|
||||
if(err!=0 && fingerprint!=17) { // hmm. 17 after powerup with oled commected and no i2c answer!?!?
|
||||
#define BM8563_ADDRESS 0x51
|
||||
Wire.beginTransmission(BM8563_ADDRESS);
|
||||
byte err = Wire.endTransmission();
|
||||
if(err==0) {
|
||||
Serial.println("M5stack Core2 board detected\n");
|
||||
config.type = TYPE_M5_CORE2;
|
||||
config.button_pin = 255;
|
||||
config.button2_pin = 255;
|
||||
config.button2_axp = 1;
|
||||
config.disptype = 4; // ILI9342
|
||||
config.oled_sda = 23;
|
||||
config.oled_scl = 18;
|
||||
config.oled_rst = -1;
|
||||
config.tft_rs = 15;
|
||||
config.tft_cs = 5;
|
||||
config.screenfile = 4;
|
||||
config.gps_rxd = 13;
|
||||
config.gps_txd = -1; // 14
|
||||
config.sx1278_ss = 33;
|
||||
config.sx1278_miso = 38;
|
||||
config.sx1278_mosi = 23; //MOSI;
|
||||
config.sx1278_sck = 18; // SCK;
|
||||
} else { // some t-beam...
|
||||
config.button_pin = 38;
|
||||
config.button2_pin = 15 + 128; //T4 + 128; // T4 = GPIO13
|
||||
// Maybe in future use as default only PWR as button2?
|
||||
//config.button2_pin = 255;
|
||||
config.button2_axp = 1;
|
||||
config.gps_rxd = 34;
|
||||
config.gps_txd = 12;
|
||||
// Check for I2C-Display@21,22
|
||||
#define SSD1306_ADDRESS 0x3c
|
||||
Wire.beginTransmission(SSD1306_ADDRESS);
|
||||
err = Wire.endTransmission();
|
||||
delay(100); // otherwise its too fast?!
|
||||
Wire.beginTransmission(SSD1306_ADDRESS);
|
||||
err = Wire.endTransmission();
|
||||
if(err!=0 && fingerprint!=17) { // hmm. 17 after powerup with oled commected and no i2c answer!?!?
|
||||
fingerprint |= 128;
|
||||
Serial.println("no I2C display found, assuming large TFT display\n");
|
||||
// CS=0, RST=14, RS=2, SDA=4, CLK=13
|
||||
|
@ -141,10 +169,11 @@ void Sonde::defaultConfig() {
|
|||
config.tft_cs = 0;
|
||||
config.spectrum = -1; // no spectrum for now on large display
|
||||
config.screenfile = 2;
|
||||
} else {
|
||||
} else {
|
||||
// OLED display, pins 21,22 ok...
|
||||
config.disptype = 0;
|
||||
Serial.println("... with small OLED display\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Serial.println("Autoconfig: looks like T-Beam v0.7 board");
|
||||
|
@ -185,7 +214,6 @@ void Sonde::defaultConfig() {
|
|||
config.startfreq=400;
|
||||
config.channelbw=10;
|
||||
config.marker=0;
|
||||
config.showafc=0;
|
||||
config.freqofs=0;
|
||||
config.rs41.agcbw=12500;
|
||||
config.rs41.rxbw=6300;
|
||||
|
@ -265,12 +293,20 @@ void Sonde::setConfig(const char *cfg) {
|
|||
config.tft_cs = atoi(val);
|
||||
} else if(strcmp(cfg,"tft_orient")==0) {
|
||||
config.tft_orient = atoi(val);
|
||||
} else if(strcmp(cfg,"tft_modeflip")==0) {
|
||||
config.tft_modeflip = atoi(val);
|
||||
} else if(strcmp(cfg,"tft_spifreq")==0) {
|
||||
config.tft_spifreq = atoi(val);
|
||||
} else if(strcmp(cfg,"gps_rxd")==0) {
|
||||
config.gps_rxd = atoi(val);
|
||||
} else if(strcmp(cfg,"gps_txd")==0) {
|
||||
config.gps_txd = atoi(val);
|
||||
} else if(strcmp(cfg,"sx1278_ss")==0) {
|
||||
config.sx1278_ss = atoi(val);
|
||||
} else if(strcmp(cfg,"sx1278_miso")==0) {
|
||||
config.sx1278_miso = atoi(val);
|
||||
} else if(strcmp(cfg,"sx1278_mosi")==0) {
|
||||
config.sx1278_mosi = atoi(val);
|
||||
} else if(strcmp(cfg,"sx1278_sck")==0) {
|
||||
config.sx1278_sck = atoi(val);
|
||||
} else if(strcmp(cfg,"maxsonde")==0) {
|
||||
config.maxsonde = atoi(val);
|
||||
if(config.maxsonde>MAXSONDE) config.maxsonde=MAXSONDE;
|
||||
|
@ -305,8 +341,6 @@ void Sonde::setConfig(const char *cfg) {
|
|||
config.spectrum = atoi(val);
|
||||
} else if(strcmp(cfg,"marker")==0) {
|
||||
config.marker = atoi(val);
|
||||
} else if(strcmp(cfg,"showafc")==0) {
|
||||
config.showafc = atoi(val);
|
||||
} else if(strcmp(cfg,"freqofs")==0) {
|
||||
config.freqofs = atoi(val);
|
||||
} else if(strcmp(cfg,"rs41.agcbw")==0) {
|
||||
|
@ -383,9 +417,11 @@ void Sonde::setConfig(const char *cfg) {
|
|||
} else if(strcmp(cfg, "sondehub.callsign")==0) {
|
||||
strncpy(config.sondehub.callsign, val, 63);
|
||||
} else if(strcmp(cfg, "sondehub.lat")==0) {
|
||||
strncpy(config.sondehub.lat, val, 19);
|
||||
config.sondehub.lat = *val==0 ? NAN : atof(val);
|
||||
Serial.printf("lat is %f\n", config.sondehub.lat);
|
||||
} else if(strcmp(cfg, "sondehub.lon")==0) {
|
||||
strncpy(config.sondehub.lon, val, 19);
|
||||
config.sondehub.lon = *val==0 ? NAN : atof(val);
|
||||
Serial.printf("lon is %f\n", config.sondehub.lon);
|
||||
} else if(strcmp(cfg, "sondehub.alt")==0) {
|
||||
strncpy(config.sondehub.alt, val, 19);
|
||||
} else if(strcmp(cfg, "sondehub.antenna")==0) {
|
||||
|
|
|
@ -67,7 +67,7 @@ typedef struct st_sondeinfo {
|
|||
// receiver configuration
|
||||
bool active;
|
||||
SondeType type;
|
||||
int8_t subtype; /* 0 for none/unknown, hex type for dfm, maybe add 1/2 for M10/M20 as well?*/
|
||||
int8_t subtype; /* 0 for none/unknown, hex type for dfm, 1/2 for M10/M20 */
|
||||
float freq;
|
||||
// decoded ID
|
||||
char typestr[5]; // decoded type (use type if *typestr==0)
|
||||
|
@ -187,14 +187,18 @@ struct st_sondehub {
|
|||
int chase;
|
||||
char host[64];
|
||||
char callsign[64];
|
||||
char lat[20];
|
||||
char lon[20];
|
||||
double lat;
|
||||
double lon;
|
||||
char alt[20];
|
||||
char antenna[64];
|
||||
char email[64];
|
||||
};
|
||||
|
||||
// to be extended
|
||||
enum { TYPE_TTGO, TYPE_M5_CORE2 };
|
||||
|
||||
typedef struct st_rdzconfig {
|
||||
int type; // autodetected type, TTGO or M5_CORE2
|
||||
// hardware configuration
|
||||
int button_pin; // PIN port number menu button (+128 for touch mode)
|
||||
int button2_pin; // PIN port number menu button (+128 for touch mode)
|
||||
|
@ -209,9 +213,13 @@ typedef struct st_rdzconfig {
|
|||
int tft_rs; // TFT RS pin
|
||||
int tft_cs; // TFT CS pin
|
||||
int tft_orient; // TFT orientation (default: 1)
|
||||
int tft_modeflip; // Hack for Joerg's strange display
|
||||
int tft_spifreq; // SPI transfer speed (default 40M is out of spec for some TFT)
|
||||
int gps_rxd; // GPS module RXD pin. We expect 9600 baud NMEA data.
|
||||
int gps_txd; // GPS module TXD pin
|
||||
int sx1278_ss; // SPI slave select for sx1278
|
||||
int sx1278_miso; // SPI MISO for sx1278
|
||||
int sx1278_mosi; // SPI MOSI for sx1278
|
||||
int sx1278_sck; // SPI SCK for sx1278
|
||||
// software configuration
|
||||
int debug; // show port and config options after reboot
|
||||
int wifi; // connect to known WLAN 0=skip
|
||||
|
@ -227,7 +235,6 @@ typedef struct st_rdzconfig {
|
|||
int noisefloor; // for spectrum display
|
||||
char mdnsname[15]; // mDNS-Name, defaults to rdzsonde
|
||||
// receiver configuration
|
||||
int showafc; // show afc value in rx screen
|
||||
int freqofs; // frequency offset (tuner config = rx frequency + freqofs) in Hz
|
||||
struct st_rs41config rs41; // configuration options specific for RS41 receiver
|
||||
struct st_rs92config rs92;
|
||||
|
|
|
@ -34,6 +34,16 @@ TTGO T-Team 1.0 with IL9225 TFT => fingerprint 23
|
|||
0:1 1:0 2:0 3:1 4:0 5:1 6:0 7:1 8:0 9:1 10:1 11:1 12:0 13:0 14:1 15:1 16:1 17:0 18:0 19:0 20:0 21:1 22:1 23:1 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:0 32:0 33:0 34:0 35:0 36:0 37:0 38:0
|
||||
0:1 1:1 2:0 3:1 4:0 5:1 6:0 7:1 8:0 9:1 10:1 11:1 12:0 13:0 14:1 15:1 16:1 17:0 18:0 19:0 20:0 21:1 22:1 23:1 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:0 32:0 33:0 34:0 35:0 36:0 37:0 38:0 (before setup)
|
||||
|
||||
M5Stack Core2
|
||||
0:1 1:0 2:0 3:1 4:1 5:1 6:0 7:1 8:0 9:1 10:1 11:1 12:0 13:1 14:1 15:1 16:1 17:0 18:1 19:0 20:0 21:1 22:1 23:1 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:0 32:0 33:0 34:0 35:0 36:0 37:0 38:0
|
||||
0:1 1:1 2:0 3:1 4:1 5:1 6:0 7:1 8:0 9:1 10:1 11:1 12:0 13:1 14:1 15:1 16:1 17:0 18:1 19:0 20:0 21:1 22:1 23:1 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:0 32:0 33:0 34:0 35:0 36:0 37:0 38:0 (before setup)
|
||||
Board fingerprint is 87 (nach power on)
|
||||
0:1 1:0 2:0 3:1 4:0 5:0 6:0 7:1 8:0 9:1 10:1 11:1 12:0 13:0 14:1 15:0 16:1 17:0 18:0 19:0 20:0 21:1 22:1 23:0 24:0 25:0 26:0 27:0 28:0 29:0 30:0 31:0 32:0 33:0 34:0 35:0 36:0 37:0 38:0
|
||||
0:1 1:1 2:0 3:1 4:0 5:0 6:0 7:1 8:0 9:1 10:1 11:1 12:0 13:0 14:1 15:0 16:1 17:0 18:0 19:0 20:0 21:1 22:1 23:0 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)
|
||||
Board fingerprint is 22 (nach reset)
|
||||
Autoconfig: looks like T-Beam 1.0 board
|
||||
|
||||
|
||||
vs 0010111
|
||||
T-Beam 1.1 seems to be different: 1110111
|
||||
GPIO4 = 1 (additional pullup) => +64
|
||||
|
|
Ładowanie…
Reference in New Issue