cleanup new config interface

pull/175/head
Hansi, dl9rdz 2021-09-18 19:52:22 +02:00
rodzic 5c5bfa0725
commit 79f5b199ae
7 zmienionych plików z 262 dodań i 210 usunięć

Wyświetl plik

@ -63,7 +63,8 @@ WiFiClient client;
#define SONDEHUB_STATION_UPDATE_TIME (60*60*1000) // 60 min
#define SONDEHUB_MOBILE_STATION_UPDATE_TIME (30*1000) // 30 sec
WiFiClient shclient; // Sondehub v2
char shImportInterval = 0, shImport = 0;
int shImportInterval = 0;
char shImport = 0;
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) to sondehub
@ -74,8 +75,8 @@ unsigned long time_last_update = 0;
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 ) )
#define SH_LOC_AUTO_IS_CHASE ( gpsPos.valid && ( (isnan(sonde.config.rxlat) || isnan(sonde.config.rxlon) ) || \
calcLatLonDist( gpsPos.lat, gpsPos.lon, sonde.config.rxlat, sonde.config.rxlon ) > MIN_LOC_AUTO_DIST ) )
#endif
extern float calcLatLonDist(float lat1, float lon1, float lat2, float lon2);
@ -154,7 +155,7 @@ String processor(const String& var) {
}
if (var == "FULLNAMEID") {
char tmp[128];
snprintf(tmp, 128, "%s-%c%d", version_id, SPIFFS_MAJOR+'A'-1, SPIFFS_MINOR);
snprintf(tmp, 128, "%s-%c%d", version_id, SPIFFS_MAJOR + 'A' - 1, SPIFFS_MINOR);
return String(tmp);
}
if (var == "AUTODETECT_INFO") {
@ -423,14 +424,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) && ( !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);
if ((*s->ser == 0) && ( !isnan(sonde.config.rxlat))) {
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.rxlat, sonde.config.rxlon);
} 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) && (!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);
if ((*s->ser == 0) && (!isnan(sonde.config.rxlat))) {
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.rxlat, sonde.config.rxlon);
} else {
sprintf(ptr, "<iframe src=\"https://sondehub.org/%s\" style=\"border:1px solid #00A3D3;border-radius:20px;height:98vh;width:100%%\"></iframe>", s-> ser);
}
@ -568,8 +569,8 @@ void setupConfigData() {
String line = readLine(file); //file.readStringUntil('\n');
sonde.setConfig(line.c_str());
}
int shII = sonde.config.sondehub.fiinterval * 60;
if(shImportInterval > shII) shImportInterval = shII;
sonde.checkConfig(); // eliminate invalid entries
shImportInterval = 5; // refresh now in 5 seconds
}
@ -682,6 +683,9 @@ struct st_configitems config_list[] = {
{"wifi", 0, &sonde.config.wifi},
{"debug", 0, &sonde.config.debug},
{"maxsonde", 0, &sonde.config.maxsonde},
{"rxlat", -7, &sonde.config.rxlat},
{"rxlon", -7, &sonde.config.rxlon},
{"rxalt", -7, &sonde.config.rxalt},
{"screenfile", 0, &sonde.config.screenfile},
{"display", -6, sonde.config.display},
/* Spectrum display settings */
@ -766,12 +770,9 @@ struct st_configitems config_list[] = {
{"sondehub.chase", 0, &sonde.config.sondehub.chase},
{"sondehub.host", 63, &sonde.config.sondehub.host},
{"sondehub.callsign", 63, &sonde.config.sondehub.callsign},
{"sondehub.lat", -7, &sonde.config.sondehub.lat},
{"sondehub.lon", -7, &sonde.config.sondehub.lon},
{"sondehub.alt", 19, &sonde.config.sondehub.alt},
{"sondehub.antenna", 63, &sonde.config.sondehub.antenna},
{"sondehub.email", 63, &sonde.config.sondehub.email},
{"sondehub.fiactive", 0, &sonde.config.sondehub.fimactitve},
{"sondehub.fiactive", 0, &sonde.config.sondehub.fiactive},
{"sondehub.fiinterval", 0, &sonde.config.sondehub.fiinterval},
{"sondehub.fimaxdist", 0, &sonde.config.sondehub.fimaxdist},
{"sondehub.fimaxage", 0, &sonde.config.sondehub.fimaxage},
@ -850,32 +851,41 @@ const char *createConfigForm() {
strcat(ptr, "<div id=\"cfgtab\"></div>");
strcat(ptr, "<script src=\"cfg.js\"></script>");
strcat(ptr, "<script>\n");
sprintf(ptr + strlen(ptr), "var scr=\"Using /screens%d.txt", 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);
}
strcat(ptr, "\";\n");
strcat(ptr, "var cf=new Map();\n");
for(int i=0; i< N_CONFIG; i++) {
for (int i = 0; i < N_CONFIG; i++) {
sprintf(ptr + strlen(ptr), "cf.set(\"%s\", \"", config_list[i].name);
switch(config_list[i].type) {
case -4:
case -3:
case -2:
case 0:
sprintf(ptr + strlen(ptr), "%d", *(int *)config_list[i].data);
break;
case -6: // list
{
int8_t *l = (int8_t *)config_list[i].data;
if(*l==-1) strcat(ptr, "0");
else { sprintf(ptr + strlen(ptr), "%d", l[0]); l++; }
while(*l != -1) {
sprintf(ptr + strlen(ptr), ",%d", *l);
l++;
}
}
break;
case -7: // double
sprintf(ptr + strlen(ptr), "%f", *(double *)config_list[i].data);
break;
default: // string
strcat(ptr, (char *)config_list[i].data);
switch (config_list[i].type) {
case -4:
case -3:
case -2:
case 0:
sprintf(ptr + strlen(ptr), "%d", *(int *)config_list[i].data);
break;
case -6: // list
{
int8_t *l = (int8_t *)config_list[i].data;
if (*l == -1) strcat(ptr, "0");
else {
sprintf(ptr + strlen(ptr), "%d", l[0]);
l++;
}
while (*l != -1) {
sprintf(ptr + strlen(ptr), ",%d", *l);
l++;
}
}
break;
case -7: // double
if (!isnan(*(double *)config_list[i].data))
sprintf(ptr + strlen(ptr), "%g", *(double *)config_list[i].data);
break;
default: // string
strcat(ptr, (char *)config_list[i].data);
}
strcat(ptr, "\");\n");
}
@ -945,7 +955,7 @@ const char *handleConfigPost(AsyncWebServerRequest *request) {
for (int i = 0; i < params; i++) {
String strlabel = request->getParam(i)->name();
const char *label = strlabel.c_str();
if(label[strlen(label)-1]=='#') continue;
if (label[strlen(label) - 1] == '#') continue;
#if 0
if (strncmp(label, "CFG", 3) != 0) continue;
int idx = atoi(label + 3);
@ -955,14 +965,14 @@ const char *handleConfigPost(AsyncWebServerRequest *request) {
AsyncWebParameter *value = request->getParam(label, true);
if (!value) continue;
String strvalue = value->value();
if( strcmp(label, "button_pin") == 0 ||
strcmp(label, "button2_pin") == 0) {
AsyncWebParameter *touch = request->getParam(strlabel+"#", true);
if(touch) {
int i = atoi(strvalue.c_str());
if(i != -1 && i != 255) i += 128;
strvalue = String(i);
}
if ( strcmp(label, "button_pin") == 0 ||
strcmp(label, "button2_pin") == 0) {
AsyncWebParameter *touch = request->getParam(strlabel + "#", true);
if (touch) {
int i = atoi(strvalue.c_str());
if (i != -1 && i != 255) i += 128;
strvalue = String(i);
}
}
#if 0
if (config_list[idx].type == -4) { // input button port with "touch" checkbox
@ -1484,7 +1494,7 @@ void SetupAsyncServer() {
if (url.endsWith(".gpx"))
request->send(200, "application/gpx+xml", sendGPX(request));
else {
// TODO: set correct type for .js
// TODO: set correct type for .js
request->send(SPIFFS, url, "text/html");
Serial.printf("URL is %s\n", url.c_str());
//request->send(404);
@ -2405,9 +2415,9 @@ void loopDecoder() {
// TODO: update displayed sonde?
#if 0
static int i=0;
if(i++>20) {
i=0;
static int i = 0;
if (i++ > 20) {
i = 0;
rtc_wdt_protect_off();
rtc_wdt_disable();
heap_caps_dump(MALLOC_CAP_8BIT);
@ -3077,7 +3087,7 @@ void execOTA() {
dispxs = dispys = 1;
char uh[17];
strncpy(uh, updateHost, 17);
uh[16]=0;
uh[16] = 0;
disp.rdis->drawString(0, 0, uh);
} else {
disp.rdis->setFont(5);
@ -3104,34 +3114,42 @@ void execOTA() {
int type = 0;
int res = fetchHTTPheader(&type);
if(res < 0) { return; }
if (res < 0) {
return;
}
// process data...
while(client.available()) {
while (client.available()) {
// get header...
char fn[128];
fn[0] = '/';
client.readBytesUntil('\n', fn+1, 128);
client.readBytesUntil('\n', fn + 1, 128);
char *sz = strchr(fn, ' ');
if(!sz) { client.stop(); return; }
if (!sz) {
client.stop();
return;
}
*sz = 0;
int len = atoi(sz+1);
int len = atoi(sz + 1);
Serial.printf("Updating file %s (%d bytes)\n", fn, len);
char fnstr[17];
memset(fnstr, ' ', 16);
strncpy(fnstr, fn, strlen(fn));
fnstr[16]=0;
fnstr[16] = 0;
disp.rdis->drawString(0, 2 * dispys, fnstr);
File f = SPIFFS.open(fn, FILE_WRITE);
// read sz bytes........
while(len>0) {
unsigned char buf[1024];
int r = client.read(buf, len>1024? 1024:len);
if(r==-1) { client.stop(); return; }
f.write(buf, r);
len -= r;
while (len > 0) {
unsigned char buf[1024];
int r = client.read(buf, len > 1024 ? 1024 : len);
if (r == -1) {
client.stop();
return;
}
f.write(buf, r);
len -= r;
}
}
client.stop();
client.stop();
Serial.print("Connecting to: "); Serial.println(updateHost);
// Connect to Update host
@ -3140,26 +3158,26 @@ void execOTA() {
return;
}
// Connection succeeded, fecthing the bin
Serial.printf("Fetching bin: %supdate.ino.bin\n", updatePrefix);
disp.rdis->drawString(0, 3 * dispys, "Fetching update");
// Connection succeeded, fecthing the bin
Serial.printf("Fetching bin: %supdate.ino.bin\n", updatePrefix);
disp.rdis->drawString(0, 3 * dispys, "Fetching update");
// Get the contents of the bin file
client.printf("GET %supdate.ino.bin HTTP/1.1\r\n"
"Host: %s\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n\r\n",
updatePrefix, updateHost);
// Get the contents of the bin file
client.printf("GET %supdate.ino.bin HTTP/1.1\r\n"
"Host: %s\r\n"
"Cache-Control: no-cache\r\n"
"Connection: close\r\n\r\n",
updatePrefix, updateHost);
// Check what is being sent
// Serial.print(String("GET ") + bin + " HTTP/1.1\r\n" +
// "Host: " + host + "\r\n" +
// "Cache-Control: no-cache\r\n" +
// "Connection: close\r\n\r\n");
// Check what is being sent
// Serial.print(String("GET ") + bin + " HTTP/1.1\r\n" +
// "Host: " + host + "\r\n" +
// "Cache-Control: no-cache\r\n" +
// "Connection: close\r\n\r\n");
int validType = 0;
contentLength = fetchHTTPheader( &validType );
if(validType==1) isValidContentType = true;
if (validType == 1) isValidContentType = true;
// Check what is the contentLength and if content type is `application/octet-stream`
Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType));
@ -3217,75 +3235,75 @@ void execOTA() {
}
int fetchHTTPheader(int *validType) {
int contentLength = -1;
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println("Client Timeout !");
client.stop();
int contentLength = -1;
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println("Client Timeout !");
client.stop();
return -1;
}
}
// Once the response is available, check stuff
/*
Response Structure
HTTP/1.1 200 OK
x-amz-id-2: NVKxnU1aIQMmpGKhSwpCBh8y2JPbak18QLIfE+OiUDOos+7UftZKjtCFqrwsGOZRN5Zee0jpTd0=
x-amz-request-id: 2D56B47560B764EC
Date: Wed, 14 Jun 2017 03:33:59 GMT
Last-Modified: Fri, 02 Jun 2017 14:50:11 GMT
ETag: "d2afebbaaebc38cd669ce36727152af9"
Accept-Ranges: bytes
Content-Type: application/octet-stream
Content-Length: 357280
Server: AmazonS3
{{BIN FILE CONTENTS}}
*/
while (client.available()) {
// read line till \n
String line = client.readStringUntil('\n');
// remove space, to check if the line is end of headers
line.trim();
// if the the line is empty,
// this is end of headers
// break the while and feed the
// remaining `client` to the
// Update.writeStream();
if (!line.length()) {
//headers ended
break; // and get the OTA started
}
// Check if the HTTP Response is 200
// else break and Exit Update
if (line.startsWith("HTTP/1.1")) {
if (line.indexOf("200") < 0) {
Serial.println("Got a non 200 status code from server. Exiting OTA Update.");
return -1;
}
}
// Once the response is available, check stuff
/*
Response Structure
HTTP/1.1 200 OK
x-amz-id-2: NVKxnU1aIQMmpGKhSwpCBh8y2JPbak18QLIfE+OiUDOos+7UftZKjtCFqrwsGOZRN5Zee0jpTd0=
x-amz-request-id: 2D56B47560B764EC
Date: Wed, 14 Jun 2017 03:33:59 GMT
Last-Modified: Fri, 02 Jun 2017 14:50:11 GMT
ETag: "d2afebbaaebc38cd669ce36727152af9"
Accept-Ranges: bytes
Content-Type: application/octet-stream
Content-Length: 357280
Server: AmazonS3
// extract headers here
// Start with content length
if (line.startsWith("Content-Length: ")) {
contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str());
Serial.println("Got " + String(contentLength) + " bytes from server");
}
{{BIN FILE CONTENTS}}
*/
while (client.available()) {
// read line till \n
String line = client.readStringUntil('\n');
// remove space, to check if the line is end of headers
line.trim();
// if the the line is empty,
// this is end of headers
// break the while and feed the
// remaining `client` to the
// Update.writeStream();
if (!line.length()) {
//headers ended
break; // and get the OTA started
}
// Check if the HTTP Response is 200
// else break and Exit Update
if (line.startsWith("HTTP/1.1")) {
if (line.indexOf("200") < 0) {
Serial.println("Got a non 200 status code from server. Exiting OTA Update.");
return -1;
}
}
// extract headers here
// Start with content length
if (line.startsWith("Content-Length: ")) {
contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str());
Serial.println("Got " + String(contentLength) + " bytes from server");
}
// Next, the content type
if (line.startsWith("Content-Type: ")) {
String contentType = getHeaderValue(line, "Content-Type: ");
Serial.println("Got " + contentType + " payload.");
if (contentType == "application/octet-stream") {
if(validType) *validType = 1;
}
// Next, the content type
if (line.startsWith("Content-Type: ")) {
String contentType = getHeaderValue(line, "Content-Type: ");
Serial.println("Got " + contentType + " payload.");
if (contentType == "application/octet-stream") {
if (validType) *validType = 1;
}
}
return contentLength;
}
return contentLength;
}
@ -3420,10 +3438,11 @@ void sondehub_station_update(WiFiClient *client, struct st_sondehub *conf) {
}
// 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]",
conf->lat, conf->lon, conf->alt[0] ? conf->alt : "null");
if ((!isnan(sonde.config.rxlat)) && (!isnan(sonde.config.rxlon))) {
if (isnan(sonde.config.rxalt))
sprintf(w, "\"uploader_position\": [%.6f,%.6f,null]", sonde.config.rxlat, sonde.config.rxlon);
else
sprintf(w, "\"uploader_position\": [%.6f,%.6f,%d]", sonde.config.rxlat, sonde.config.rxlon, (int)sonde.config.rxalt);
} else {
sprintf(w, "\"uploader_position\": [null,null,null]");
}
@ -3477,12 +3496,15 @@ const char *dfmSubtypeStrSH[16] = { NULL, NULL, NULL, NULL, NULL, NULL,
void sondehub_handle_fimport(WiFiClient *client) {
if (sonde.config.sondehub.fiactive) {
Serial.printf("shimp: %d %d\n", shImport, shImportInterval);
if (shImport == 0) {
sondehub_send_fimport(&shclient);
} else if (shImport == 1) {
int res = ShFreqImport::shImportHandleReply(&shclient);
Serial.printf("ret: %d\n", res);
if (res == 1) {
shImport = 2; // finished
shImportInterval = sonde.config.sondehub.fiinterval * 60;
}
} else if (shImport == 2) {
// waiting for next activation...
@ -3502,7 +3524,7 @@ void sondehub_send_fimport(WiFiClient * client) {
return;
}
// It's time to run, so check prerequisites
float lat = sonde.config.sondehub.lat, lon = sonde.config.sondehub.lon;
float lat = sonde.config.rxlat, lon = sonde.config.rxlon;
if (gpsPos.valid) {
lat = gpsPos.lat;
lon = gpsPos.lon;
@ -3510,8 +3532,9 @@ void sondehub_send_fimport(WiFiClient * client) {
int maxdist = sonde.config.sondehub.fimaxdist; // km
int maxage = sonde.config.sondehub.fimaxage * 60; // fimaxage is hours, shImportSendRequest uses minutes
int shImportInterval = sonde.config.sondehub.fiinterval * 60; // shImportInterval is in seconds, fiinterval in minutes
if ( !isnan(lat) && !isnan(lon) && maxdist > 0 && maxage > 0 && shImportInterval > 0 ) {
int fiinterval = sonde.config.sondehub.fiinterval;
Serial.printf("shimp : %f %f %d %d %d\n", lat, lon, maxdist, maxage, shImportInterval);
if ( !isnan(lat) && !isnan(lon) && maxdist > 0 && maxage > 0 && fiinterval > 0 ) {
int res = ShFreqImport::shImportSendRequest(&shclient, lat, lon, maxdist, maxage);
if (res == 0) shImport = 1; // Request OK: wait for response
else shImport = 2; // Request failed: wait interval, then retry
@ -3557,8 +3580,8 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub *
// If something that looks like a valid HTTP response is received, we are ready to send the next data item
if (shState == SH_CONN_WAITACK && cnt > 11 && strncmp(rs_msg, "HTTP/1", 6) == 0) {
shState = SH_CONN_IDLE;
if( sonde.config.sondehub.fiactive)
sondehub_send_fimport(client);
if ( sonde.config.sondehub.fiactive)
sondehub_send_fimport(client);
}
}
@ -3686,10 +3709,11 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub *
}
// 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]",
conf->lat, conf->lon, conf->alt[0] ? conf->alt : "null");
if ((!isnan(sonde.config.rxlat)) && (!isnan(sonde.config.rxlon))) {
if (isnan(sonde.config.rxalt))
sprintf(w, "\"uploader_position\": [%.6f,%.6f,null]", sonde.config.rxlat, sonde.config.rxlon);
else
sprintf(w, "\"uploader_position\": [%.6f,%.6f,%d]", sonde.config.rxlat, sonde.config.rxlon, (int)sonde.config.rxalt);
} else {
sprintf(w, "\"uploader_position\": [null,null,null]");
}
@ -3742,8 +3766,8 @@ void sondehub_send_header(WiFiClient * client, SondeInfo * s, struct st_sondehub
"Host: ");
Serial.println(conf->host);
Serial.print("accept: text/plain\r\n"
"Content-Type: application/json\r\n"
"Transfer-Encoding: chunked\r\n");
"Content-Type: application/json\r\n"
"Transfer-Encoding: chunked\r\n");
client->print("PUT /sondes/telemetry HTTP/1.1\r\n"
"Host: ");

Wyświetl plik

@ -1,10 +1,18 @@
var cfgs = [
[ "", "Software configuration" ],
[ "wifi", "Wifi mode (0=off, 1=client, 2=AP, 3=auto client/AP on startup" ],
[ "", "General configuration" ],
[ "wifi", "Wifi mode (0=off, 1=client, 2=AP, 3=client or AP autoselect on startup)" ],
[ "mdnsname", "Network mDNS name"],
[ "ephftp", "FTP server for ephemeris data (RS92 decoder)"],
[ "debug", "Debug mode (0/1)" ],
[ "maxsonde", "max. number of QRG entries (must be <100)" ],
[ "maxsonde", "Maxumum number of QRG entries (must be <100)" ],
[ "rxlat", "Receiver fixed latitude"],
[ "rxlon", "Receiver fixed longitude"],
[ "rxalt", "Receiver fixed altitude"],
[ "", "OLED/TFT display configuration" ],
[ "screenfile", "Screen config (0=automatic; 1-5=predefined; other=custom)" ],
[ "display", "Display screens (scan, default, ...)" ],
[ "norx_timeout", "No-RX-timeout in seconds (-1=disabled)"],
[ "tft_orient", "TFT orientation (0/1/2/3), OLED flip: 3"],
[ "", "Spectrum display settings" ],
[ "spectrum", "Show spectrum on start (-1=no, 0=forever, >0=time [sec])" ],
[ "startfreq", "Start frequency (MHz, default 400)" ],
@ -23,38 +31,48 @@ var cfgs = [
[ "m10m20.rxbw", "M10/M20 RX bandwidth"],
[ "mp3h.agcbw", "MP3H AGC bandwidth"],
[ "mp3h.rxbw", "MP3H RX bandwidth"],
[ "ephftp", "FTP for eph (RS92)"],
[ "", "Data feed configuration"],
[ "", "KISS TNC/AXUDP/AXTCP data feed configuration"],
[ "call", "Call"],
[ "passcode", "Passcode"],
[ "kisstnc.active", "KISS TNC (port 14590) (needs reboot)"],
[ "kisstnc.idformat", "KISS TNC ID Format"],
[ "kisstnc.idformat", "KISS TNC ID format"],
[ "axudp.active", "AXUDP active"],
[ "axudp.host", "AXUDP Host"],
[ "axudp.port", "AXUDP Port"],
[ "axudp.idformat", "DFM ID Format"],
[ "axudp.host", "AXUDP host"],
[ "axudp.port", "AXUDP port"],
[ "axudp.idformat", "DFM ID format"],
[ "axudp.highrate", "Rate limit"],
[ "tcp.active", "APRS TCP active"],
[ "tcp.host", "ARPS TCP Host"],
[ "tcp.port", "APRS TCP Port"],
[ "tcp.idformat", "DFM ID Format"],
[ "tcp.host", "ARPS TCP host"],
[ "tcp.port", "APRS TCP port"],
[ "tcp.idformat", "DFM ID format"],
[ "tcp.highrate", "Rate limit"],
[ "mqtt.active", "MQTT Active (needs reboot)"],
[ "", "MQTT data feed configuration"],
[ "mqtt.active", "MQTT active (needs reboot)"],
[ "mqtt.id", "MQTT client ID"],
[ "mqtt.host", "MQTT server hostname"],
[ "mqtt.port", "MQTT Port"],
[ "mqtt.username", "MQTT Username"],
[ "mqtt.password", "MQTT Password"],
[ "mqtt.prefix", "MQTT Prefix"],
[ "mqtt.port", "MQTT port"],
[ "mqtt.username", "MQTT username"],
[ "mqtt.password", "MQTT password"],
[ "mqtt.prefix", "MQTT prefix"],
[ "", "SondeHub settings"],
[ "sondehub.active", "SondeHub reporting (0=disabled, 1=active)"],
[ "sondehub.chase", "SondeHub location reporting (0=off, 1=fixed, 2=chase/GPS, 3=auto)"],
[ "sondehub.host", "SondeHub host (DO NOT CHANGE)"],
[ "sondehub.callsign", "Callsign"],
[ "sondehub.antenna", "Antenna (optional, visisble on SondeHub tracker)"],
[ "sondehub.email", "SondeHub email (optional, only used to contact in case of upload errors)"],
[ "", "SondeHub frequency import" ],
[ "sondehub.fiactive", "SondeHub frequency import active (0=disabled, 1=active)" ],
[ "sondehub.fiinterval", "Import frequency (minutes, &geq; 5)" ],
[ "sondehub.fimaxdist", "Import maximum distance (km, &leq; 500)" ],
[ "sondehub.fimaxage", "Import maximum age (hours, &leq; 24)" ],
[ "", "Hardware configuration (requires reboot)"],
[ "disptype", "Display type (0=OLED/SSD1306, 1=ILI9225, 2=OLED/SH1106, 3=ILI9341, 4=ILI9342)"],
[ "norx_timeout", "No-RX-Timeout in seconds (-1=disabled)"],
[ "oled_sda", "OLED SDA/TFT SDA"],
[ "oled_scl", "OLED SCL/TFT CLK"],
[ "oled_rst", "OLED RST/TFT RST (needs reboot)"],
[ "tft_rs", "TFT RS"],
[ "tft_cs", "TFT CS"],
[ "tft_orient", "TFT orientation (0/1/2/3), OLED flip: 3"],
[ "tft_spifreq", "TFT SPI speed"],
[ "button_pin", "Button input port"],
[ "button2_pin", "Button 2 input port"],
@ -69,26 +87,10 @@ var cfgs = [
[ "sx1278_miso", "SX1278 MISO"],
[ "sx1278_mosi", "SX1278 MOSI"],
[ "sx1278_sck", "SX1278 SCK"],
[ "mdnsname", "mDNS name"],
[ "", "SondeHub settings"],
[ "sondehub.active", "SondeHub reporting (0=disabled, 1=active)"],
[ "sondehub.chase", "SondeHub location reporting (0=off, 1=fixed, 2=chase/GPS, 3=auto)"],
[ "sondehub.host", "SondeHub host (DO NOT CHANGE)"],
[ "sondehub.callsign", "Callsign"],
[ "sondehub.lat", "Latitude (optional, required to show station on SondeHub Tracker)"],
[ "sondehub.lon", "Longitude (optional, required to show station on SondeHub Tracker)"],
[ "sondehub.alt", "Altitude (optional, visible on SondeHub tracker)"],
[ "sondehub.antenna", "Antenna (optional, visisble on SondeHub tracker)"],
[ "sondehub.email", "SondeHub email (optional, only used to contact in case of upload errors)"],
[ "", "SondeHub frequency import" ],]
[ "sondehub.fiactive", "SondeHub frequency import active (0=disabled, 1=active)" ],
[ "sondehub.fiinterval", "Import frequency (minutes, &geq;5)" ],
[ "sondehub.fimaxdist", "Import maximum distance (km, &leq;500)" ],
[ "sondehub.fimaxage", "Import maximum age (hours, &leq;24" ],
];
function mkcfg(id, key, label, value) {
var s = "<tr class=\"cfgpanel\"><td>" + label + "</td><td><input name=\"" + key + "\" type=\"text\" value=\"" + value + "\"/></td></tr>\n";
var s = "<tr style=\"visibility: collapse;\" class=\"cfgpanel\"><td>" + label + "</td><td><input name=\"" + key + "\" type=\"text\" value=\"" + value + "\"/></td></tr>\n";
return s;
}
function mkcfgbtn(id, key, label, value) {
@ -98,13 +100,13 @@ function mkcfgbtn(id, key, label, value) {
touch = " checked";
v = v & 127;
}
var s = "<tr class=\"cfgpanel\"><td>" + label + "</td><td><input name=\"" + key + "\" type=\"text\" size=\"3\" value=\"" + v + "\"/>";
var s = "<tr style=\"visibility:collapse\" class=\"cfgpanel\"><td>" + label + "</td><td><input name=\"" + key + "\" type=\"text\" size=\"3\" value=\"" + v + "\"/>";
s += "<input type=\"checkbox\" name=\"" + key + "#\" "+touch+"> Touch</td></tr>\n";
return s;
}
function mksep(id,label) {
return "<tr class=\"cfgheader\"><th align=\"left\" colspan=\"2\">"+label+"</th></tr>\n";
return "<tr class=\"cfgheader\"><th class=\"cfg\" align=\"left\" colspan=\"2\">"+label+"</th></tr>\n";
}
function rowdisp(id,disp) {
var matches = document.querySelectorAll("tr."+id);
@ -122,10 +124,14 @@ function configTable() {
var key = cfgs[i][0];
var lbl = cfgs[i][1];
if(key) {
if(key=="button_pin" || key=="button2_pin")
if(key=="button_pin" || key=="button2_pin") {
tab += mkcfgbtn("s"+id, key, lbl, cf.get(key));
else
} else if (key=="display") {
tab += mkcfg("s"+id, key, lbl, cf.get(key));
tab += "<tr style=\"visibility:collapse\" class=\"cfgpanel\"><td>"+scr+"</td><td></td></tr>"
} else {
tab += mkcfg("s"+id, key, lbl, cf.get(key));
}
} else {
id++;
tab += mksep("s"+id, lbl);
@ -137,11 +143,11 @@ function configTable() {
// enable collapse / expand of items below a header
var acc = document.getElementsByClassName("cfgheader");
for(i=0; i<acc.length; i++) {
acc[i].firstChild.innerHTML = "\u2212 " + acc[i].firstChild.innerHTML;
acc[i].firstChild.innerHTML = "[+] " + acc[i].firstChild.innerHTML;
acc[i].addEventListener("click", function() {
achar = "\u2212";
if(this.classList.toggle("active")) achar = "+";
this.firstChild.innerHTML = achar + this.firstChild.innerHTML.substring(1);
achar = "[+]";
if(this.classList.toggle("active")) achar = "[\u2212]";
this.firstChild.innerHTML = achar + this.firstChild.innerHTML.substring(3);
var panel = this;
console.log(panel);
while( panel = panel.nextElementSibling) {
@ -156,4 +162,5 @@ function configTable() {
}
});
}
acc[0].click();
}

Wyświetl plik

@ -24,6 +24,9 @@
#oled_rst=16
#tft_rs=2
#tft_cs=0
rxlat=
rxlon=
rxalt=
tft_orient=1
#tft_spifreq=40000000
#gps_rxd=-1
@ -124,9 +127,6 @@ sondehub.active=0
sondehub.chase=3
sondehub.host=api.v2.sondehub.org
sondehub.callsign=CHANGEME_RDZTTGO
sondehub.lat=
sondehub.lon=
sondehub.alt=
sondehub.antenna=
sondehub.email=
#-------------------------------#

Wyświetl plik

@ -10,6 +10,10 @@ body, html {
.cfgpanel {
}
th.cfg {
padding:5pt
}
.hamburger {
position: relative;
display: inline-block;

Wyświetl plik

@ -114,10 +114,12 @@ void ShFreqImport::cleanup() {
#define BUFLEN 128
#define VALLEN 20
int ShFreqImport::handleChar(char c) {
Serial.print(c);
switch(importState) {
case START:
// wait for initial '{'
if(c=='{') {
Serial.println("{ found");
lat = NAN; lon = NAN; freq = NAN; *type = 0;
importState++;
}
@ -125,7 +127,11 @@ int ShFreqImport::handleChar(char c) {
case BEFOREID:
// what for first '"' in { "A1234567" : { ... } }; or detect end
if(c=='"') { idpos = 0; importState++; }
if(c=='}') { importState = ENDREACHED; }
if(c=='}') {
importState = ENDREACHED;
cleanup();
return 1;
}
break;
case COPYID:
// copy ID "A1234567" until second '"' is earched
@ -196,6 +202,7 @@ int ShFreqImport::handleChar(char c) {
else if (c=='}') { importState = ENDREACHED; cleanup(); return 1; }
break;
case ENDREACHED:
Serial.println("REPLY: END REACHED");
return 1;
}
return 0;
@ -228,6 +235,7 @@ int ShFreqImport::shImportSendRequest(WiFiClient *client, float lat, float lon,
// return 0 if more data should be read (later), 1 if finished (close connection...)
int ShFreqImport::shImportHandleReply(WiFiClient *client) {
if(!client->connected()) return 1;
while(client->available()) {
int res = handleChar(client->read());
if(res) return res;

Wyświetl plik

@ -263,6 +263,13 @@ void Sonde::defaultConfig() {
extern struct st_configitems config_list[];
extern const int N_CONFIG;
void Sonde::checkConfig() {
if(config.maxsonde > MAXSONDE) config.maxsonde = MAXSONDE;
if(config.sondehub.fiinterval<5) config.sondehub.fiinterval = 5;
if(config.sondehub.fimaxdist>500) config.sondehub.fimaxdist = 500;
if(config.sondehub.fimaxdist==0) config.sondehub.fimaxdist = 150;
if(config.sondehub.fimaxage==0) config.sondehub.fimaxage = 2;
}
void Sonde::setConfig(const char *cfg) {
while(*cfg==' '||*cfg=='\t') cfg++;
if(*cfg=='#') return;
@ -288,10 +295,11 @@ void Sonde::setConfig(const char *cfg) {
case -3: // integer (boolean on/off swith in web form)
case -2: // integer (ID type)
*(int *)config_list[i].data = atoi(val);
if(config.maxsonde > MAXSONDE) config.maxsonde = MAXSONDE;
break;
case -7: // double
*(double *)config_list[i].data = *val==0 ? NAN : atof(val);
double d = atof(val);
if(*val == 0 || d==0) d = NAN;
*(double *)config_list[i].data = d;
break;
case -6: // display list
{

Wyświetl plik

@ -191,9 +191,6 @@ struct st_sondehub {
int chase;
char host[64];
char callsign[64];
double lat;
double lon;
char alt[20];
char antenna[64];
char email[64];
int fiactive;
@ -231,6 +228,9 @@ typedef struct st_rdzconfig {
int sx1278_sck; // SPI SCK for sx1278
// software configuration
int debug; // show port and config options after reboot
double rxlat;
double rxlon;
double rxalt;
int wifi; // connect to known WLAN 0=skip
int screenfile;
int8_t display[30]; // list of display mode (0:scanner, 1:default, 2,... additional modes)
@ -295,6 +295,7 @@ public:
Sonde();
void defaultConfig();
void checkConfig();
void setConfig(const char *str);
void clearSonde();