kopia lustrzana https://github.com/dl9rdz/rdz_ttgo_sonde
cleanup new config interface
rodzic
5c5bfa0725
commit
79f5b199ae
|
@ -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: ");
|
||||
|
|
|
@ -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, ≥ 5)" ],
|
||||
[ "sondehub.fimaxdist", "Import maximum distance (km, ≤ 500)" ],
|
||||
[ "sondehub.fimaxage", "Import maximum age (hours, ≤ 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, ≥5)" ],
|
||||
[ "sondehub.fimaxdist", "Import maximum distance (km, ≤500)" ],
|
||||
[ "sondehub.fimaxage", "Import maximum age (hours, ≤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();
|
||||
}
|
||||
|
|
|
@ -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=
|
||||
#-------------------------------#
|
||||
|
|
|
@ -10,6 +10,10 @@ body, html {
|
|||
.cfgpanel {
|
||||
}
|
||||
|
||||
th.cfg {
|
||||
padding:5pt
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
Ładowanie…
Reference in New Issue