kopia lustrzana https://github.com/dl9rdz/rdz_ttgo_sonde
Merge branch 'dl9rdz:devel' into devel
commit
0291c96f50
|
@ -436,16 +436,16 @@ const char *createSondeHubMap() {
|
||||||
HTMLBODY(ptr, "map.html");
|
HTMLBODY(ptr, "map.html");
|
||||||
if (!sonde.config.sondehub.active) {
|
if (!sonde.config.sondehub.active) {
|
||||||
strcat(ptr, "<div>NOTE: SondeHub uploading is not enabled, detected sonde will not be visable on map</div>");
|
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.rxlat))) {
|
if ((*s->d.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);
|
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 {
|
} else {
|
||||||
sprintf(ptr + strlen(ptr), "<iframe src=\"https://sondehub.org/%s\" style=\"border:1px solid #00A3D3;border-radius:20px;height:95vh\"></iframe>", s-> ser);
|
sprintf(ptr + strlen(ptr), "<iframe src=\"https://sondehub.org/%s\" style=\"border:1px solid #00A3D3;border-radius:20px;height:95vh\"></iframe>", s->d.ser);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((*s->ser == 0) && (!isnan(sonde.config.rxlat))) {
|
if ((*s->d.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);
|
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 {
|
} else {
|
||||||
sprintf(ptr, "<iframe src=\"https://sondehub.org/%s\" style=\"border:1px solid #00A3D3;border-radius:20px;height:98vh;width:100%%\"></iframe>", s-> ser);
|
sprintf(ptr, "<iframe src=\"https://sondehub.org/%s\" style=\"border:1px solid #00A3D3;border-radius:20px;height:98vh;width:100%%\"></iframe>", s->d.ser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HTMLBODYEND(ptr);
|
HTMLBODYEND(ptr);
|
||||||
|
@ -497,24 +497,24 @@ void addSondeStatus(char *ptr, int i)
|
||||||
SondeInfo *s = &sonde.sondeList[i];
|
SondeInfo *s = &sonde.sondeList[i];
|
||||||
strcat(ptr, "<table>");
|
strcat(ptr, "<table>");
|
||||||
sprintf(ptr + strlen(ptr), "<tr><td id=\"sfreq\">%3.3f MHz, Type: %s</td><tr><td>ID: %s", s->freq, sondeTypeLongStr[s->type],
|
sprintf(ptr + strlen(ptr), "<tr><td id=\"sfreq\">%3.3f MHz, Type: %s</td><tr><td>ID: %s", s->freq, sondeTypeLongStr[s->type],
|
||||||
s->validID ? s->id : "<?""?>");
|
s->d.validID ? s->d.id : "<?""?>");
|
||||||
if (s->validID && (TYPE_IS_DFM(s->type) || TYPE_IS_METEO(s->type) || s->type == STYPE_MP3H) ) {
|
if (s->d.validID && (TYPE_IS_DFM(s->type) || TYPE_IS_METEO(s->type) || s->type == STYPE_MP3H) ) {
|
||||||
sprintf(ptr + strlen(ptr), " (ser: %s)", s->ser);
|
sprintf(ptr + strlen(ptr), " (ser: %s)", s->d.ser);
|
||||||
}
|
}
|
||||||
sprintf(ptr + strlen(ptr), "</td></tr><tr><td>QTH: %.6f,%.6f h=%.0fm</td></tr>\n", s->lat, s->lon, s->alt);
|
sprintf(ptr + strlen(ptr), "</td></tr><tr><td>QTH: %.6f,%.6f h=%.0fm</td></tr>\n", s->d.lat, s->d.lon, s->d.alt);
|
||||||
const time_t t = s->time;
|
const time_t t = s->d.time;
|
||||||
ts = *gmtime(&t);
|
ts = *gmtime(&t);
|
||||||
sprintf(ptr + strlen(ptr), "<tr><td>Frame# %u, Sats=%d, %04d-%02d-%02d %02d:%02d:%02d</td></tr>",
|
sprintf(ptr + strlen(ptr), "<tr><td>Frame# %u, Sats=%d, %04d-%02d-%02d %02d:%02d:%02d</td></tr>",
|
||||||
s->frame, s->sats, ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
|
s->d.frame, s->d.sats, ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
|
||||||
if (s->type == STYPE_RS41) {
|
if (s->type == STYPE_RS41) {
|
||||||
sprintf(ptr + strlen(ptr), "<tr><td>Burst-KT=%d Launch-KT=%d Countdown=%d (vor %ds)</td></tr>\n",
|
sprintf(ptr + strlen(ptr), "<tr><td>Burst-KT=%d Launch-KT=%d Countdown=%d (vor %ds)</td></tr>\n",
|
||||||
s->burstKT, s->launchKT, s->countKT, ((uint16_t)s->frame - s->crefKT));
|
s->d.burstKT, s->d.launchKT, s->d.countKT, ((uint16_t)s->d.frame - s->d.crefKT));
|
||||||
}
|
}
|
||||||
sprintf(ptr + strlen(ptr), "<tr><td><a target=\"_empty\" href=\"geo:%.6f,%.6f\">GEO-App</a> - ", s->lat, s->lon);
|
sprintf(ptr + strlen(ptr), "<tr><td><a target=\"_empty\" href=\"geo:%.6f,%.6f\">GEO-App</a> - ", s->d.lat, s->d.lon);
|
||||||
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://radiosondy.info/sonde_archive.php?sondenumber=%s\">radiosondy.info</a> - ", s->id);
|
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://radiosondy.info/sonde_archive.php?sondenumber=%s\">radiosondy.info</a> - ", s->d.id);
|
||||||
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://tracker.sondehub.org/%s\">SondeHub Tracker</a> - ", s->ser);
|
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://tracker.sondehub.org/%s\">SondeHub Tracker</a> - ", s->d.ser);
|
||||||
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://www.openstreetmap.org/?mlat=%.6f&mlon=%.6f&zoom=14\">OSM</a> - ", s->lat, s->lon);
|
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://www.openstreetmap.org/?mlat=%.6f&mlon=%.6f&zoom=14\">OSM</a> - ", s->d.lat, s->d.lon);
|
||||||
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://www.google.com/maps/search/?api=1&query=%.6f,%.6f\">Google</a></td></tr>", s->lat, s->lon);
|
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://www.google.com/maps/search/?api=1&query=%.6f,%.6f\">Google</a></td></tr>", s->d.lat, s->d.lon);
|
||||||
|
|
||||||
strcat(ptr, "</table><p/>\n");
|
strcat(ptr, "</table><p/>\n");
|
||||||
}
|
}
|
||||||
|
@ -542,7 +542,7 @@ const char *createLiveJson() {
|
||||||
SondeInfo *s = &sonde.sondeList[sonde.currentSonde];
|
SondeInfo *s = &sonde.sondeList[sonde.currentSonde];
|
||||||
sprintf(ptr + strlen(ptr), "\"sonde\": {\"rssi\": %d, \"vframe\": %d, \"time\": %d,\"id\": \"%s\", \"freq\": %3.3f, \"type\": \"%s\","
|
sprintf(ptr + strlen(ptr), "\"sonde\": {\"rssi\": %d, \"vframe\": %d, \"time\": %d,\"id\": \"%s\", \"freq\": %3.3f, \"type\": \"%s\","
|
||||||
"\"lat\": %.6f, \"lon\": %.6f, \"alt\": %.0f, \"speed\": %.1f, \"dir\": %.0f, \"climb\": %.1f, \"launchsite\": \"%s\", \"res\": %d }",
|
"\"lat\": %.6f, \"lon\": %.6f, \"alt\": %.0f, \"speed\": %.1f, \"dir\": %.0f, \"climb\": %.1f, \"launchsite\": \"%s\", \"res\": %d }",
|
||||||
s->rssi, s->vframe, s->time, s->id, s->freq, sondeTypeStr[s->type], s->lat, s->lon, s->alt, s->hs, s->dir, s->vs, s->launchsite, s->rxStat[0]);
|
s->rssi, s->d.vframe, s->d.time, s->d.id, s->freq, sondeTypeStr[s->type], s->d.lat, s->d.lon, s->d.alt, s->d.hs, s->d.dir, s->d.vs, s->launchsite, s->rxStat[0]);
|
||||||
|
|
||||||
if (gpsPos.valid) {
|
if (gpsPos.valid) {
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -1295,15 +1295,15 @@ void addSondeStatusKML(char *ptr, int i)
|
||||||
{
|
{
|
||||||
SondeInfo *s = &sonde.sondeList[i];
|
SondeInfo *s = &sonde.sondeList[i];
|
||||||
|
|
||||||
if (!s->validID)
|
if (!s->d.validID)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(ptr + strlen(ptr), "<Placemark id=\"%s\"><name>%s</name><Point><altitudeMode>absolute</altitudeMode><coordinates>%.6f,%.6f,%.0f</coordinates></Point><description>%3.3f MHz, Type: %s, h=%.0fm</description></Placemark>",
|
sprintf(ptr + strlen(ptr), "<Placemark id=\"%s\"><name>%s</name><Point><altitudeMode>absolute</altitudeMode><coordinates>%.6f,%.6f,%.0f</coordinates></Point><description>%3.3f MHz, Type: %s, h=%.0fm</description></Placemark>",
|
||||||
s->id, s->id,
|
s->d.id, s->d.id,
|
||||||
s->lon, s->lat, s->alt,
|
s->d.lon, s->d.lat, s->d.alt,
|
||||||
s->freq, sondeTypeStr[s->type], s->alt);
|
s->freq, sondeTypeStr[s->type], s->d.alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *createKMLDynamic() {
|
const char *createKMLDynamic() {
|
||||||
|
@ -1333,8 +1333,8 @@ const char *sendGPX(AsyncWebServerRequest * request) {
|
||||||
return "ERROR";
|
return "ERROR";
|
||||||
}
|
}
|
||||||
SondeInfo *si = &sonde.sondeList[index];
|
SondeInfo *si = &sonde.sondeList[index];
|
||||||
strcpy(si->id, "test");
|
strcpy(si->d.id, "test");
|
||||||
si->lat = 48; si->lon = 11; si->alt = 500;
|
si->d.lat = 48; si->d.lon = 11; si->d.alt = 500;
|
||||||
snprintf(ptr, 10240, "<?xml version='1.0' encoding='UTF-8'?>\n"
|
snprintf(ptr, 10240, "<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||||
"<gpx version=\"1.1\" creator=\"http://rdzsonde.local\" xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
"<gpx version=\"1.1\" creator=\"http://rdzsonde.local\" xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
||||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||||
|
@ -1344,7 +1344,7 @@ const char *sendGPX(AsyncWebServerRequest * request) {
|
||||||
"<author>rdzTTGOsonde</author>\n"
|
"<author>rdzTTGOsonde</author>\n"
|
||||||
"</metadata>\n"
|
"</metadata>\n"
|
||||||
"<wpt lat=\"%f\" lon=\"%f\">\n <ele>%f</ele>\n <name>%s</name>\n <sym>Radio Beacon</sym><type>Sonde</type>\n"
|
"<wpt lat=\"%f\" lon=\"%f\">\n <ele>%f</ele>\n <name>%s</name>\n <sym>Radio Beacon</sym><type>Sonde</type>\n"
|
||||||
"</wpt></gpx>\n", index, si->id, si->lat, si->lon, si->alt, si->id);
|
"</wpt></gpx>\n", index, si->d.id, si->d.lat, si->d.lon, si->d.alt, si->d.id);
|
||||||
Serial.println(message);
|
Serial.println(message);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
@ -2504,7 +2504,7 @@ void loopDecoder() {
|
||||||
//Send a packet with position information
|
//Send a packet with position information
|
||||||
// first check if ID and position lat+lonis ok
|
// first check if ID and position lat+lonis ok
|
||||||
|
|
||||||
if (s->validID && ((s->validPos & 0x03) == 0x03)) {
|
if (s->d.validID && ((s->d.validPos & 0x03) == 0x03)) {
|
||||||
const char *str = aprs_senddata(s, sonde.config.call, sonde.config.udpfeed.symbol);
|
const char *str = aprs_senddata(s, sonde.config.call, sonde.config.udpfeed.symbol);
|
||||||
if (connected) {
|
if (connected) {
|
||||||
char raw[201];
|
char raw[201];
|
||||||
|
@ -2551,7 +2551,7 @@ void loopDecoder() {
|
||||||
Serial.println("Sending position via TCP as rdzJSON");
|
Serial.println("Sending position via TCP as rdzJSON");
|
||||||
char raw[1024];
|
char raw[1024];
|
||||||
char gps[128];
|
char gps[128];
|
||||||
const char *typestr = s->typestr;
|
const char *typestr = s->d.typestr;
|
||||||
if (*typestr == 0) typestr = sondeTypeStr[s->type];
|
if (*typestr == 0) typestr = sondeTypeStr[s->type];
|
||||||
// TODO: only if GPS is valid...
|
// TODO: only if GPS is valid...
|
||||||
if (gpsPos.valid) {
|
if (gpsPos.valid) {
|
||||||
|
@ -2597,27 +2597,27 @@ void loopDecoder() {
|
||||||
typestr,
|
typestr,
|
||||||
(int)s->active,
|
(int)s->active,
|
||||||
s->freq,
|
s->freq,
|
||||||
s->id,
|
s->d.id,
|
||||||
s->ser,
|
s->d.ser,
|
||||||
(int)s->validID,
|
(int)s->d.validID,
|
||||||
s->launchsite,
|
s->launchsite,
|
||||||
s->lat,
|
s->d.lat,
|
||||||
s->lon,
|
s->d.lon,
|
||||||
s->alt,
|
s->d.alt,
|
||||||
s->vs,
|
s->d.vs,
|
||||||
s->hs,
|
s->d.hs,
|
||||||
s->dir,
|
s->d.dir,
|
||||||
s->sats,
|
s->d.sats,
|
||||||
s->validPos,
|
s->d.validPos,
|
||||||
s->time,
|
s->d.time,
|
||||||
s->frame,
|
s->d.frame,
|
||||||
(int)s->validTime,
|
(int)s->d.validTime,
|
||||||
s->rssi,
|
s->rssi,
|
||||||
s->afc,
|
s->afc,
|
||||||
s->launchKT,
|
s->d.launchKT,
|
||||||
s->burstKT,
|
s->d.burstKT,
|
||||||
s->countKT,
|
s->d.countKT,
|
||||||
s->crefKT,
|
s->d.crefKT,
|
||||||
gps
|
gps
|
||||||
);
|
);
|
||||||
//Serial.println("Writing rdzclient...");
|
//Serial.println("Writing rdzclient...");
|
||||||
|
@ -3603,12 +3603,12 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub *
|
||||||
uint8_t realtype = s->type;
|
uint8_t realtype = s->type;
|
||||||
// config setting M10 and M20 will both decode both types, so use the real type that was decoded
|
// config setting M10 and M20 will both decode both types, so use the real type that was decoded
|
||||||
if (TYPE_IS_METEO(realtype)) {
|
if (TYPE_IS_METEO(realtype)) {
|
||||||
realtype = s->subtype == 1 ? STYPE_M10 : STYPE_M20;
|
realtype = s->d.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 DFM, s->d.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
|
// For all others, sec should always be 0 and time the exact time in seconds
|
||||||
time_t t = s->time;
|
time_t t = s->d.time;
|
||||||
|
|
||||||
int chase = conf->chase;
|
int chase = conf->chase;
|
||||||
// automatically decided if CHASE or FIXED mode is used (for config AUTO)
|
// automatically decided if CHASE or FIXED mode is used (for config AUTO)
|
||||||
|
@ -3627,11 +3627,11 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub *
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if current sonde data is valid. If not, don't do anything....
|
// Check if current sonde data is valid. If not, don't do anything....
|
||||||
if (*s->ser == 0) return; // Don't send anything without serial number
|
if (*s->d.ser == 0) return; // Don't send anything without serial number
|
||||||
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->d.lat == 0) && ((int)s->d.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
|
if ((int)s->d.alt > 50000) return; // If alt is too high don't send to SondeHub
|
||||||
// M20 data does not include #sat information
|
// M20 data does not include #sat information
|
||||||
if ( realtype != STYPE_M20 && (int)s->sats < 4) return; // If not enough sats don't send to SondeHub
|
if ( realtype != STYPE_M20 && (int)s->d.sats < 4) return; // If not enough sats don't send to SondeHub
|
||||||
|
|
||||||
// If not connected to sondehub, try reconnecting.
|
// If not connected to sondehub, try reconnecting.
|
||||||
// TODO: do this outside of main loop
|
// TODO: do this outside of main loop
|
||||||
|
@ -3651,8 +3651,8 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub *
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( abs(now - (time_t)s->time) > (3600 * SONDEHUB_TIME_THRESHOLD) ) {
|
if ( abs(now - (time_t)s->d.time) > (3600 * SONDEHUB_TIME_THRESHOLD) ) {
|
||||||
Serial.printf("Sonde time %d too far from current UTC time %ld", s->time, now);
|
Serial.printf("Sonde time %d too far from current UTC time %ld", s->d.time, now);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3688,25 +3688,25 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub *
|
||||||
"\"type\": \"%s\",",
|
"\"type\": \"%s\",",
|
||||||
version_name, version_id, conf->callsign,
|
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,
|
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
|
||||||
manufacturer_string[realtype], s->ser,
|
manufacturer_string[realtype], s->d.ser,
|
||||||
ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec,
|
ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec,
|
||||||
(float)s->lat, (float)s->lon, (float)s->alt, (float)s->freq, (float)s->hs, (float)s->vs,
|
(float)s->d.lat, (float)s->d.lon, (float)s->d.alt, (float)s->freq, (float)s->d.hs, (float)s->d.vs,
|
||||||
(float)s->dir, -((float)s->rssi / 2), s->vframe, sondeTypeStrSH[realtype]
|
(float)s->d.dir, -((float)s->rssi / 2), s->d.vframe, sondeTypeStrSH[realtype]
|
||||||
);
|
);
|
||||||
w += strlen(w);
|
w += strlen(w);
|
||||||
|
|
||||||
// Only send sats if not M20
|
// Only send sats if not M20
|
||||||
if (realtype != STYPE_M20) {
|
if (realtype != STYPE_M20) {
|
||||||
sprintf(w, "\"sats\": %d,", (int)s->sats);
|
sprintf(w, "\"sats\": %d,", (int)s->d.sats);
|
||||||
w += strlen(w);
|
w += strlen(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if there is a subtype (DFM only) */
|
/* if there is a subtype (DFM only) */
|
||||||
if ( TYPE_IS_DFM(s->type) && s->subtype > 0 && s->subtype < 16 ) {
|
if ( TYPE_IS_DFM(s->type) && s->d.subtype > 0 && s->d.subtype < 16 ) {
|
||||||
const char *t = dfmSubtypeStrSH[s->subtype];
|
const char *t = dfmSubtypeStrSH[s->d.subtype];
|
||||||
// as in https://github.com/projecthorus/radiosonde_auto_rx/blob/e680221f69a568e1fdb24e76db679233f32cb027/auto_rx/autorx/sonde_specific.py#L84
|
// as in https://github.com/projecthorus/radiosonde_auto_rx/blob/e680221f69a568e1fdb24e76db679233f32cb027/auto_rx/autorx/sonde_specific.py#L84
|
||||||
if (t) sprintf(w, "\"subtype\": \"%s\",", t);
|
if (t) sprintf(w, "\"subtype\": \"%s\",", t);
|
||||||
else sprintf(w, "\"subtype\": \"DFMx%X\",", s->subtype); // Unknown subtype
|
else sprintf(w, "\"subtype\": \"DFMx%X\",", s->d.subtype); // Unknown subtype
|
||||||
w += strlen(w);
|
w += strlen(w);
|
||||||
} else if ( s->type == STYPE_RS41 ) {
|
} else if ( s->type == STYPE_RS41 ) {
|
||||||
char buf[11];
|
char buf[11];
|
||||||
|
@ -3717,26 +3717,26 @@ void sondehub_send_data(WiFiClient * client, SondeInfo * s, struct st_sondehub *
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only send temp if provided
|
// Only send temp if provided
|
||||||
if ((int)s->temperature != 0) {
|
if ((int)s->d.temperature != 0) {
|
||||||
sprintf(w, "\"temp\": %.3f,", float(s->temperature));
|
sprintf(w, "\"temp\": %.1f,", float(s->d.temperature));
|
||||||
w += strlen(w);
|
w += strlen(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only send humidity if provided
|
// Only send humidity if provided
|
||||||
if ((int)s->relativeHumidity != 0) {
|
if ((int)s->d.relativeHumidity != 0) {
|
||||||
sprintf(w, "\"humidity\": %.3f,", float(s->relativeHumidity));
|
sprintf(w, "\"humidity\": %.1f,", float(s->d.relativeHumidity));
|
||||||
w += strlen(w);
|
w += strlen(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only send burst timer if RS41 and fresh within the last 51s
|
// Only send burst timer if RS41 and fresh within the last 51s
|
||||||
if ((realtype == STYPE_RS41) && (s->crefKT > 0) && (s->vframe - s->crefKT < 51)) {
|
if ((realtype == STYPE_RS41) && (s->d.crefKT > 0) && (s->d.vframe - s->d.crefKT < 51)) {
|
||||||
sprintf(w, "\"burst_timer\": %d,", (int)s->countKT);
|
sprintf(w, "\"burst_timer\": %d,", (int)s->d.countKT);
|
||||||
w += strlen(w);
|
w += strlen(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only send battery if provided
|
// Only send battery if provided
|
||||||
if (s->batteryVoltage > 0) {
|
if (s->d.batteryVoltage > 0) {
|
||||||
sprintf(w, "\"batt\": %.2f,", s->batteryVoltage);
|
sprintf(w, "\"batt\": %.2f,", s->d.batteryVoltage);
|
||||||
w += strlen(w);
|
w += strlen(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@ extern const char *sondeTypeStrSH[];
|
||||||
int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
|
int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
struct tm tim;
|
struct tm tim;
|
||||||
time_t t = si->time;
|
time_t t = si->d.time;
|
||||||
gmtime_r(&t, &tim);
|
gmtime_r(&t, &tim);
|
||||||
uint8_t realtype = si->type;
|
uint8_t realtype = si->type;
|
||||||
if (TYPE_IS_METEO(realtype)) {
|
if (TYPE_IS_METEO(realtype)) {
|
||||||
realtype = si->subtype == 1 ? STYPE_M10 : STYPE_M20;
|
realtype = si->d.subtype == 1 ? STYPE_M10 : STYPE_M20;
|
||||||
}
|
}
|
||||||
sprintf(buf, "{ \"type\": \"PAYLOAD_SUMMARY\","
|
sprintf(buf, "{ \"type\": \"PAYLOAD_SUMMARY\","
|
||||||
"\"callsign\": \"%s\","
|
"\"callsign\": \"%s\","
|
||||||
|
@ -22,16 +22,16 @@ int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
|
||||||
"\"model\": \"%s\","
|
"\"model\": \"%s\","
|
||||||
"\"freq\": \"%.3f MHz\","
|
"\"freq\": \"%.3f MHz\","
|
||||||
"\"temp\": %g }",
|
"\"temp\": %g }",
|
||||||
si->ser,
|
si->d.ser,
|
||||||
si->lat,
|
si->d.lat,
|
||||||
si->lon,
|
si->d.lon,
|
||||||
(int)si->alt,
|
(int)si->d.alt,
|
||||||
(int)(si->hs * 1.9438445), // m/s into knots
|
(int)(si->d.hs * 1.9438445), // m/s into knots
|
||||||
(int)si->dir,
|
(int)si->d.dir,
|
||||||
tim.tm_hour, tim.tm_min, tim.tm_sec,
|
tim.tm_hour, tim.tm_min, tim.tm_sec,
|
||||||
sondeTypeStrSH[realtype],
|
sondeTypeStrSH[realtype],
|
||||||
si->freq,
|
si->freq,
|
||||||
si->temperature);
|
si->d.temperature);
|
||||||
Serial.printf("Sending chasemapper json: %s\n", buf);
|
Serial.printf("Sending chasemapper json: %s\n", buf);
|
||||||
udp.beginPacket(sonde.config.cm.host, sonde.config.cm.port);
|
udp.beginPacket(sonde.config.cm.host, sonde.config.cm.port);
|
||||||
udp.write((const uint8_t *)buf, strlen(buf));
|
udp.write((const uint8_t *)buf, strlen(buf));
|
||||||
|
|
|
@ -209,6 +209,7 @@ void DFM::finddfname(uint8_t *b)
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t ix;
|
uint8_t ix;
|
||||||
uint16_t d;
|
uint16_t d;
|
||||||
|
SondeData *sd = &(sonde.si()->d);
|
||||||
|
|
||||||
st = b[0]; /* frame start byte */
|
st = b[0]; /* frame start byte */
|
||||||
ix = b[3]; /* hi/lo part of ser; (LSB due to our bitsToBytes...) */
|
ix = b[3]; /* hi/lo part of ser; (LSB due to our bitsToBytes...) */
|
||||||
|
@ -242,10 +243,10 @@ void DFM::finddfname(uint8_t *b)
|
||||||
chkid >>= 4;
|
chkid >>= 4;
|
||||||
}
|
}
|
||||||
if(i==6) {
|
if(i==6) {
|
||||||
snprintf(sonde.si()->id, 10, "D%x ", id);
|
snprintf(sd->id, 10, "D%x ", id);
|
||||||
sonde.si()->validID = true;
|
sd->validID = true;
|
||||||
sonde.si()->subtype = (st>>4)&0x0F;
|
sd->subtype = (st>>4)&0x0F;
|
||||||
strncpy(sonde.si()->typestr, typestr[ (st>>4)&0x0F ], 5);
|
strncpy(sd->typestr, typestr[ (st>>4)&0x0F ], 5);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dfmstate.lastfrcnt = 0;
|
dfmstate.lastfrcnt = 0;
|
||||||
|
@ -291,12 +292,12 @@ void DFM::finddfname(uint8_t *b)
|
||||||
dfmstate.idcnt1 = dfmstate.cnt[2*i+1];
|
dfmstate.idcnt1 = dfmstate.cnt[2*i+1];
|
||||||
dfmstate.nameregok = i;
|
dfmstate.nameregok = i;
|
||||||
// generate id.....
|
// generate id.....
|
||||||
snprintf(sonde.si()->id, 10, "D%d", ((dfmstate.dat[2*i]<<16)|dfmstate.dat[2*i+1])%100000000);
|
snprintf(sd->id, 10, "D%d", ((dfmstate.dat[2*i]<<16)|dfmstate.dat[2*i+1])%100000000);
|
||||||
Serial.print("\nNEW AUTOID:");
|
Serial.print("\nNEW AUTOID:");
|
||||||
Serial.println(sonde.si()->id);
|
Serial.println(sd->id);
|
||||||
sonde.si()->validID = true;
|
sd->validID = true;
|
||||||
sonde.si()->subtype = (st>>4)&0x0F;
|
sd->subtype = (st>>4)&0x0F;
|
||||||
strncpy(sonde.si()->typestr, typestr[ (st>>4)&0x0F ], 5);
|
strncpy(sd->typestr, typestr[ (st>>4)&0x0F ], 5);
|
||||||
}
|
}
|
||||||
if(dfmstate.nameregok==i) {
|
if(dfmstate.nameregok==i) {
|
||||||
Serial.print(" ID OK");
|
Serial.print(" ID OK");
|
||||||
|
@ -327,7 +328,7 @@ void DFM::decodeCFG(uint8_t *cfg)
|
||||||
// new ID
|
// new ID
|
||||||
finddfname(cfg);
|
finddfname(cfg);
|
||||||
// new aprs ID (dxlaprs, autorx) is now "D" + serial (8 digits) by consensus
|
// new aprs ID (dxlaprs, autorx) is now "D" + serial (8 digits) by consensus
|
||||||
memcpy(sonde.si()->ser, sonde.si()->id+1, 9);
|
memcpy(sonde.si()->d.ser, sonde.si()->d.id+1, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bitCount(int x) {
|
static int bitCount(int x) {
|
||||||
|
@ -342,7 +343,8 @@ uint16_t MON[]={0,0,31,59,90,120,151,181,212,243,273,304,334};
|
||||||
|
|
||||||
void DFM::decodeDAT(uint8_t *dat)
|
void DFM::decodeDAT(uint8_t *dat)
|
||||||
{
|
{
|
||||||
SondeInfo *si = sonde.si();
|
// TODO: Here we need to work on a shadow copy of SondeData in order to prevent concurrent changes while using data in main loop
|
||||||
|
SondeData *si = &(sonde.si()->d);
|
||||||
Serial.print(" DAT["); Serial.print(dat[6]); Serial.print("]: ");
|
Serial.print(" DAT["); Serial.print(dat[6]); Serial.print("]: ");
|
||||||
// We can have a 8 and 0 subframe in a single frame. So do the reset only for dat>0
|
// We can have a 8 and 0 subframe in a single frame. So do the reset only for dat>0
|
||||||
if( !(dat[6]==0 && dfmstate.lastdat==8) ) { // if we have DAT8 + DAT0, don't reset before returing the 8 frame...
|
if( !(dat[6]==0 && dfmstate.lastdat==8) ) { // if we have DAT8 + DAT0, don't reset before returing the 8 frame...
|
||||||
|
|
|
@ -1125,41 +1125,41 @@ void Display::drawString(DispEntry *de, const char *str) {
|
||||||
|
|
||||||
void Display::drawLat(DispEntry *de) {
|
void Display::drawLat(DispEntry *de) {
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
if(!sonde.si()->validPos) {
|
if(!sonde.si()->d.validPos) {
|
||||||
drawString(de,"<?""?> ");
|
drawString(de,"<?""?> ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
snprintf(buf, 16, "%2.5f", sonde.si()->lat);
|
snprintf(buf, 16, "%2.5f", sonde.si()->d.lat);
|
||||||
drawString(de,buf);
|
drawString(de,buf);
|
||||||
}
|
}
|
||||||
void Display::drawLon(DispEntry *de) {
|
void Display::drawLon(DispEntry *de) {
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
if(!sonde.si()->validPos) {
|
if(!sonde.si()->d.validPos) {
|
||||||
drawString(de,"<?""?> ");
|
drawString(de,"<?""?> ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
snprintf(buf, 16, "%2.5f", sonde.si()->lon);
|
snprintf(buf, 16, "%2.5f", sonde.si()->d.lon);
|
||||||
drawString(de,buf);
|
drawString(de,buf);
|
||||||
}
|
}
|
||||||
void Display::drawAlt(DispEntry *de) {
|
void Display::drawAlt(DispEntry *de) {
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
if(!sonde.si()->validPos) {
|
if(!sonde.si()->d.validPos) {
|
||||||
drawString(de," ");
|
drawString(de," ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float alt = sonde.si()->alt;
|
float alt = sonde.si()->d.alt;
|
||||||
//testing only.... alt += 30000-454;
|
//testing only.... alt += 30000-454;
|
||||||
snprintf(buf, 16, alt>=1000?" %5.0fm":" %3.1fm", alt);
|
snprintf(buf, 16, alt>=1000?" %5.0fm":" %3.1fm", alt);
|
||||||
drawString(de,buf+strlen(buf)-6);
|
drawString(de,buf+strlen(buf)-6);
|
||||||
}
|
}
|
||||||
void Display::drawHS(DispEntry *de) {
|
void Display::drawHS(DispEntry *de) {
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
if(!sonde.si()->validPos) {
|
if(!sonde.si()->d.validPos) {
|
||||||
drawString(de," ");
|
drawString(de," ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean is_ms = (de->extra && de->extra[0]=='m')?true:false; // m/s or km/h
|
boolean is_ms = (de->extra && de->extra[0]=='m')?true:false; // m/s or km/h
|
||||||
float hs = sonde.si()->hs;
|
float hs = sonde.si()->d.hs;
|
||||||
if(!is_ms) hs = hs * 3.6;
|
if(!is_ms) hs = hs * 3.6;
|
||||||
boolean has_extra = (de->extra && de->extra[1]!=0)? true: false;
|
boolean has_extra = (de->extra && de->extra[1]!=0)? true: false;
|
||||||
snprintf(buf, 16, hs>99?" %3.0f":" %2.1f", hs);
|
snprintf(buf, 16, hs>99?" %3.0f":" %2.1f", hs);
|
||||||
|
@ -1169,11 +1169,11 @@ void Display::drawHS(DispEntry *de) {
|
||||||
}
|
}
|
||||||
void Display::drawVS(DispEntry *de) {
|
void Display::drawVS(DispEntry *de) {
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
if(!sonde.si()->validPos) {
|
if(!sonde.si()->d.validPos) {
|
||||||
drawString(de," ");
|
drawString(de," ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
snprintf(buf, 16, " %+2.1f", sonde.si()->vs);
|
snprintf(buf, 16, " %+2.1f", sonde.si()->d.vs);
|
||||||
DebugPrintf(DEBUG_DISPLAY, "drawVS: extra is %s width=%d\n", de->extra?de->extra:"<null>", de->width);
|
DebugPrintf(DEBUG_DISPLAY, "drawVS: extra is %s width=%d\n", de->extra?de->extra:"<null>", de->width);
|
||||||
if(de->extra) { strcat(buf, de->extra); }
|
if(de->extra) { strcat(buf, de->extra); }
|
||||||
drawString(de, buf+strlen(buf)-5- (de->extra?strlen(de->extra):0) );
|
drawString(de, buf+strlen(buf)-5- (de->extra?strlen(de->extra):0) );
|
||||||
|
@ -1181,29 +1181,29 @@ void Display::drawVS(DispEntry *de) {
|
||||||
}
|
}
|
||||||
void Display::drawID(DispEntry *de) {
|
void Display::drawID(DispEntry *de) {
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
if(!sonde.si()->validID) {
|
if(!sonde.si()->d.validID) {
|
||||||
drawString(de, "nnnnnnnn ");
|
drawString(de, "nnnnnnnn ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(de->extra && de->extra[0]=='n') {
|
if(de->extra && de->extra[0]=='n') {
|
||||||
// real serial number, as printed on sonde, can be up to 11 digits long
|
// real serial number, as printed on sonde, can be up to 11 digits long
|
||||||
drawString(de, sonde.si()->ser);
|
drawString(de, sonde.si()->d.ser);
|
||||||
} else if (de->extra && de->extra[0]=='s') {
|
} else if (de->extra && de->extra[0]=='s') {
|
||||||
// short ID, max 8 digits (no initial "D" for DFM, "M" instead of "ME" for M10)
|
// short ID, max 8 digits (no initial "D" for DFM, "M" instead of "ME" for M10)
|
||||||
if( TYPE_IS_DFM(sonde.si()->type) ) {
|
if( TYPE_IS_DFM(sonde.si()->type) ) {
|
||||||
drawString(de, sonde.si()->id+1);
|
drawString(de, sonde.si()->d.id+1);
|
||||||
} else if (TYPE_IS_METEO(sonde.si()->type)) {
|
} else if (TYPE_IS_METEO(sonde.si()->type)) {
|
||||||
char sid[9];
|
char sid[9];
|
||||||
sid[0]='M';
|
sid[0]='M';
|
||||||
memcpy(sid+1, sonde.si()->id+2, 8);
|
memcpy(sid+1, sonde.si()->d.id+2, 8);
|
||||||
sid[8] = 0;
|
sid[8] = 0;
|
||||||
drawString(de, sid);
|
drawString(de, sid);
|
||||||
} else {
|
} else {
|
||||||
drawString(de, sonde.si()->id);
|
drawString(de, sonde.si()->d.id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// dxlAPRS sonde number, max 9 digits, as used on aprs.fi and radiosondy.info
|
// dxlAPRS sonde number, max 9 digits, as used on aprs.fi and radiosondy.info
|
||||||
drawString(de, sonde.si()->id);
|
drawString(de, sonde.si()->d.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Display::drawRSSI(DispEntry *de) {
|
void Display::drawRSSI(DispEntry *de) {
|
||||||
|
@ -1230,7 +1230,7 @@ void Display::drawQS(DispEntry *de) {
|
||||||
|
|
||||||
void Display::drawType(DispEntry *de) {
|
void Display::drawType(DispEntry *de) {
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
const char *typestr = sonde.si()->typestr;
|
const char *typestr = sonde.si()->d.typestr;
|
||||||
if(*typestr==0) typestr = sondeTypeStr[sonde.si()->type];
|
if(*typestr==0) typestr = sondeTypeStr[sonde.si()->type];
|
||||||
drawString(de, typestr);
|
drawString(de, typestr);
|
||||||
}
|
}
|
||||||
|
@ -1289,9 +1289,9 @@ void Display::drawKilltimer(DispEntry *de) {
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
uint16_t value=0;
|
uint16_t value=0;
|
||||||
switch(de->extra[0]) {
|
switch(de->extra[0]) {
|
||||||
case 'l': value = sonde.si()->launchKT; break;
|
case 'l': value = sonde.si()->d.launchKT; break;
|
||||||
case 'b': value = sonde.si()->burstKT; break;
|
case 'b': value = sonde.si()->d.burstKT; break;
|
||||||
case 'c': value = sonde.si()->countKT; break;
|
case 'c': value = sonde.si()->d.countKT; break;
|
||||||
}
|
}
|
||||||
// format: 4=h:mm; 6=h:mm:ss; s=sssss
|
// format: 4=h:mm; 6=h:mm:ss; s=sssss
|
||||||
uint16_t h=value/3600;
|
uint16_t h=value/3600;
|
||||||
|
@ -1362,17 +1362,17 @@ static int tmpc=0;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
// distance
|
// distance
|
||||||
if( gpsPos.valid && (sonde.si()->validPos&0x03)==0x03 && (layout->usegps&GPSUSE_DIST)) {
|
if( gpsPos.valid && (sonde.si()->d.validPos&0x03)==0x03 && (layout->usegps&GPSUSE_DIST)) {
|
||||||
gpsDist = (int)calcLatLonDist(gpsPos.lat, gpsPos.lon, sonde.si()->lat, sonde.si()->lon);
|
gpsDist = (int)calcLatLonDist(gpsPos.lat, gpsPos.lon, sonde.si()->d.lat, sonde.si()->d.lon);
|
||||||
} else {
|
} else {
|
||||||
gpsDist = -1;
|
gpsDist = -1;
|
||||||
}
|
}
|
||||||
// bearing
|
// bearing
|
||||||
if( gpsPos.valid && (sonde.si()->validPos&0x03)==0x03 && (layout->usegps&GPSUSE_BEARING)) {
|
if( gpsPos.valid && (sonde.si()->d.validPos&0x03)==0x03 && (layout->usegps&GPSUSE_BEARING)) {
|
||||||
float lat1 = radians(gpsPos.lat);
|
float lat1 = radians(gpsPos.lat);
|
||||||
float lat2 = radians(sonde.si()->lat);
|
float lat2 = radians(sonde.si()->d.lat);
|
||||||
float lon1 = radians(gpsPos.lon);
|
float lon1 = radians(gpsPos.lon);
|
||||||
float lon2 = radians(sonde.si()->lon);
|
float lon2 = radians(sonde.si()->d.lon);
|
||||||
float y = sin(lon2-lon1)*cos(lat2);
|
float y = sin(lon2-lon1)*cos(lat2);
|
||||||
float x = cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(lon2-lon1);
|
float x = cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(lon2-lon1);
|
||||||
float dir = atan2(y, x)/PI*180;
|
float dir = atan2(y, x)/PI*180;
|
||||||
|
@ -1425,7 +1425,7 @@ void Display::drawGPS(DispEntry *de) {
|
||||||
{
|
{
|
||||||
// distance
|
// distance
|
||||||
// equirectangular approximation is good enough
|
// equirectangular approximation is good enough
|
||||||
if( (sonde.si()->validPos&0x03)!=0x03 ) {
|
if( (sonde.si()->d.validPos&0x03)!=0x03 ) {
|
||||||
snprintf(buf, 16, "no pos ");
|
snprintf(buf, 16, "no pos ");
|
||||||
if(de->extra && *de->extra=='5') buf[5]=0;
|
if(de->extra && *de->extra=='5') buf[5]=0;
|
||||||
} else if(!gpsPos.valid) {
|
} else if(!gpsPos.valid) {
|
||||||
|
@ -1448,7 +1448,7 @@ void Display::drawGPS(DispEntry *de) {
|
||||||
break;
|
break;
|
||||||
case 'I':
|
case 'I':
|
||||||
// dIrection
|
// dIrection
|
||||||
if( (!gpsPos.valid) || ((sonde.si()->validPos&0x03)!=0x03 ) ) {
|
if( (!gpsPos.valid) || ((sonde.si()->d.validPos&0x03)!=0x03 ) ) {
|
||||||
drawString(de, "---");
|
drawString(de, "---");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1460,7 +1460,7 @@ void Display::drawGPS(DispEntry *de) {
|
||||||
break;
|
break;
|
||||||
case 'B':
|
case 'B':
|
||||||
// relative bearing
|
// relative bearing
|
||||||
if( (!gpsPos.valid) || ((sonde.si()->validPos&0x03)!=0x03 ) ) {
|
if( (!gpsPos.valid) || ((sonde.si()->d.validPos&0x03)!=0x03 ) ) {
|
||||||
drawString(de, "---");
|
drawString(de, "---");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1491,9 +1491,9 @@ void Display::drawGPS(DispEntry *de) {
|
||||||
int angN, angA, angB; // angle of north, array, bullet
|
int angN, angA, angB; // angle of north, array, bullet
|
||||||
int validA, validB; // 0: no, 1: yes, -1: old
|
int validA, validB; // 0: no, 1: yes, -1: old
|
||||||
if(circinfo->arr=='C') { angA=gpsPos.course; validA=disp.gpsCourseOld?-1:1; }
|
if(circinfo->arr=='C') { angA=gpsPos.course; validA=disp.gpsCourseOld?-1:1; }
|
||||||
else { angA=disp.gpsDir; validA=sonde.si()->validPos?(rxgood?1:-1):0; }
|
else { angA=disp.gpsDir; validA=sonde.si()->d.validPos?(rxgood?1:-1):0; }
|
||||||
if(circinfo->bul=='C') { angB=gpsPos.course; validB=disp.gpsCourseOld?-1:1; }
|
if(circinfo->bul=='C') { angB=gpsPos.course; validB=disp.gpsCourseOld?-1:1; }
|
||||||
else { angB=disp.gpsDir; validB=sonde.si()->validPos?(rxgood?1:-1):0; }
|
else { angB=disp.gpsDir; validB=sonde.si()->d.validPos?(rxgood?1:-1):0; }
|
||||||
if(circinfo->top=='N') {
|
if(circinfo->top=='N') {
|
||||||
angN = 0;
|
angN = 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -280,7 +280,9 @@ int M10M20::decodeframeM10(uint8_t *data) {
|
||||||
|
|
||||||
if(data[1]==0x9F && data[2]==0x20) {
|
if(data[1]==0x9F && data[2]==0x20) {
|
||||||
Serial.println("Decoding...");
|
Serial.println("Decoding...");
|
||||||
SondeInfo *si = sonde.si();
|
//SondeInfo *si = sonde.si();
|
||||||
|
SondeData *si = &(sonde.si()->d);
|
||||||
|
|
||||||
// Its a M10
|
// Its a M10
|
||||||
// getid...
|
// getid...
|
||||||
char ids[12];
|
char ids[12];
|
||||||
|
@ -295,7 +297,7 @@ int M10M20::decodeframeM10(uint8_t *data) {
|
||||||
ids[7] = hex(id/16);
|
ids[7] = hex(id/16);
|
||||||
ids[8] = hex(id);
|
ids[8] = hex(id);
|
||||||
ids[9] = 0;
|
ids[9] = 0;
|
||||||
strncpy(sonde.si()->id, ids, 10);
|
strncpy(si->id, ids, 10);
|
||||||
ids[0] = hex(data[95]/16);
|
ids[0] = hex(data[95]/16);
|
||||||
ids[1] = dez((data[95]&0x0f)/10);
|
ids[1] = dez((data[95]&0x0f)/10);
|
||||||
ids[2] = dez((data[95]&0x0f));
|
ids[2] = dez((data[95]&0x0f));
|
||||||
|
@ -396,15 +398,15 @@ void M10M20::processM10data(uint8_t dt)
|
||||||
// 45 20 7x => M20
|
// 45 20 7x => M20
|
||||||
if(rxp==2 && dataptr[0]==0x45 && dataptr[1]==0x20) { isM20 = true; }
|
if(rxp==2 && dataptr[0]==0x45 && dataptr[1]==0x20) { isM20 = true; }
|
||||||
if(isM20) {
|
if(isM20) {
|
||||||
memcpy(sonde.si()->typestr, "M20 ", 5);
|
memcpy(sonde.si()->d.typestr, "M20 ", 5);
|
||||||
sonde.si()->subtype = 2;
|
sonde.si()->d.subtype = 2;
|
||||||
if(rxp>=M20_FRAMELEN) {
|
if(rxp>=M20_FRAMELEN) {
|
||||||
rxsearching = true;
|
rxsearching = true;
|
||||||
haveNewFrame = decodeframeM20(dataptr);
|
haveNewFrame = decodeframeM20(dataptr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(sonde.si()->typestr, "M10 ", 5);
|
memcpy(sonde.si()->d.typestr, "M10 ", 5);
|
||||||
sonde.si()->subtype = 1;
|
sonde.si()->d.subtype = 1;
|
||||||
if(rxp>=M10_FRAMELEN) {
|
if(rxp>=M10_FRAMELEN) {
|
||||||
rxsearching = true;
|
rxsearching = true;
|
||||||
haveNewFrame = decodeframeM10(dataptr);
|
haveNewFrame = decodeframeM10(dataptr);
|
||||||
|
@ -472,7 +474,8 @@ int M10M20::decodeframeM20(uint8_t *data) {
|
||||||
int repl = 0;
|
int repl = 0;
|
||||||
bool crcok = false;
|
bool crcok = false;
|
||||||
bool crcbok = false;
|
bool crcbok = false;
|
||||||
SondeInfo *si = sonde.si();
|
//SondeInfo *si = sonde.si();
|
||||||
|
SondeData *si = &(sonde.si()->d);
|
||||||
// error correction, inspired by oe5dxl's sondeudp
|
// error correction, inspired by oe5dxl's sondeudp
|
||||||
// check first block
|
// check first block
|
||||||
uint8_t s[200];
|
uint8_t s[200];
|
||||||
|
@ -569,7 +572,7 @@ int M10M20::decodeframeM20(uint8_t *data) {
|
||||||
uint32_t tow = getint24(data+15);
|
uint32_t tow = getint24(data+15);
|
||||||
uint16_t week = getint16(data+26);
|
uint16_t week = getint16(data+26);
|
||||||
si->time = (tow+week*604800+315964800)-18;
|
si->time = (tow+week*604800+315964800)-18;
|
||||||
si->vframe = sonde.si()->time - 315964800;
|
si->vframe =si->time - 315964800;
|
||||||
|
|
||||||
si->validTime = true;
|
si->validTime = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,7 +199,8 @@ extern double atang2(double x, double y);
|
||||||
|
|
||||||
|
|
||||||
void calcgps(uint8_t *buf) {
|
void calcgps(uint8_t *buf) {
|
||||||
SondeInfo *si = sonde.si();
|
//SondeInfo *si = sonde.si();
|
||||||
|
SondeData *si =&(sonde.si()->d);
|
||||||
double wx = i4(buf+pos_GPSecefX) * 0.01;
|
double wx = i4(buf+pos_GPSecefX) * 0.01;
|
||||||
double wy = i4(buf+pos_GPSecefY) * 0.01;
|
double wy = i4(buf+pos_GPSecefY) * 0.01;
|
||||||
double wz = i4(buf+pos_GPSecefZ) * 0.01;
|
double wz = i4(buf+pos_GPSecefZ) * 0.01;
|
||||||
|
@ -237,7 +238,8 @@ static uint32_t getgpstime(uint8_t *buf) {
|
||||||
}
|
}
|
||||||
// unix time stamp from date and time info in frame.
|
// unix time stamp from date and time info in frame.
|
||||||
static void getmp3htime(uint8_t *buf) {
|
static void getmp3htime(uint8_t *buf) {
|
||||||
SondeInfo *si = sonde.si();
|
//SondeInfo *si = sonde.si();
|
||||||
|
SondeData *si =&(sonde.si()->d);
|
||||||
|
|
||||||
// gpsdate from CFG frame 15 (0 if not yet received)
|
// gpsdate from CFG frame 15 (0 if not yet received)
|
||||||
uint32_t gpsdate = mp3hstate.gpsdate;
|
uint32_t gpsdate = mp3hstate.gpsdate;
|
||||||
|
@ -285,7 +287,8 @@ int MP3H::decodeframeMP3H(uint8_t *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// data is a frame with correct CRC
|
// data is a frame with correct CRC
|
||||||
SondeInfo *si = sonde.si();
|
//SondeInfo *si = sonde.si();
|
||||||
|
SondeData *si =&(sonde.si()->d);
|
||||||
uint8_t cnt = data[pos_CNT1] & 0x0F;
|
uint8_t cnt = data[pos_CNT1] & 0x0F;
|
||||||
uint32_t cfg = u4(data+pos_CFG);
|
uint32_t cfg = u4(data+pos_CFG);
|
||||||
if(cnt==15) {
|
if(cnt==15) {
|
||||||
|
@ -307,7 +310,7 @@ int MP3H::decodeframeMP3H(uint8_t *data) {
|
||||||
// get id
|
// get id
|
||||||
if((mp3hstate.idok&3) == 3) {
|
if((mp3hstate.idok&3) == 3) {
|
||||||
//...
|
//...
|
||||||
si->type = STYPE_MP3H;
|
//si->type = STYPE_MP3H;
|
||||||
uint32_t n = mp3hstate.id1*100000 + mp3hstate.id2;
|
uint32_t n = mp3hstate.id1*100000 + mp3hstate.id2;
|
||||||
si->id[0] = 'M';
|
si->id[0] = 'M';
|
||||||
si->id[1] = 'R';
|
si->id[1] = 'R';
|
||||||
|
@ -504,13 +507,13 @@ int MP3H::receive() {
|
||||||
if(haveNewFrame != 1) {
|
if(haveNewFrame != 1) {
|
||||||
Serial.printf("hNF: %d (ERROR)\n", haveNewFrame);
|
Serial.printf("hNF: %d (ERROR)\n", haveNewFrame);
|
||||||
retval = RX_ERROR;
|
retval = RX_ERROR;
|
||||||
} else if (sonde.si()->time == lastFrame) { // same frame number as seen before => skip
|
} else if (sonde.si()->d.time == lastFrame) { // same frame number as seen before => skip
|
||||||
Serial.printf("Skipping frame with frame# %d\n", lastFrame);
|
Serial.printf("Skipping frame with frame# %d\n", lastFrame);
|
||||||
// nothing, wait for next, "new" frame
|
// nothing, wait for next, "new" frame
|
||||||
} else { // good and new frame, return it.
|
} else { // good and new frame, return it.
|
||||||
Serial.println("Good frame");
|
Serial.println("Good frame");
|
||||||
haveNewFrame = 0;
|
haveNewFrame = 0;
|
||||||
lastFrame = sonde.si()->time;
|
lastFrame = sonde.si()->d.time;
|
||||||
return RX_OK;
|
return RX_OK;
|
||||||
}
|
}
|
||||||
haveNewFrame = 0;
|
haveNewFrame = 0;
|
||||||
|
|
|
@ -431,7 +431,7 @@ static void posrs41(const byte b[], uint32_t b_len, uint32_t p)
|
||||||
double z;
|
double z;
|
||||||
double y;
|
double y;
|
||||||
double x;
|
double x;
|
||||||
SondeInfo *si = sonde.si();
|
SondeData *si = &(sonde.si()->d);
|
||||||
x = (double)getint32(b, b_len, p)*0.01;
|
x = (double)getint32(b, b_len, p)*0.01;
|
||||||
y = (double)getint32(b, b_len, p+4UL)*0.01;
|
y = (double)getint32(b, b_len, p+4UL)*0.01;
|
||||||
z = (double)getint32(b, b_len, p+8UL)*0.01;
|
z = (double)getint32(b, b_len, p+8UL)*0.01;
|
||||||
|
@ -594,7 +594,7 @@ float GetRAHumidity( uint32_t humCurrent, uint32_t humMin, uint32_t humMax, floa
|
||||||
float Cp = ( C / calibration->value.calibU[0] - 1.0f) * calibration->value.calibU[1];
|
float Cp = ( C / calibration->value.calibU[0] - 1.0f) * calibration->value.calibU[1];
|
||||||
|
|
||||||
/* Compensation for low temperature and pressure at altitude */
|
/* Compensation for low temperature and pressure at altitude */
|
||||||
float estimatedPressure = 1013.25f * expf(-1.18575919e-4f * sonde.si()->alt );
|
float estimatedPressure = 1013.25f * expf(-1.18575919e-4f * sonde.si()->d.alt );
|
||||||
|
|
||||||
float Tp = (sensorTemp - 20.0f) / 180.0f;
|
float Tp = (sensorTemp - 20.0f) / 180.0f;
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
|
@ -640,7 +640,7 @@ int RS41::decode41(byte *data, int maxlen)
|
||||||
{
|
{
|
||||||
char buf[128];
|
char buf[128];
|
||||||
int crcok = 0;
|
int crcok = 0;
|
||||||
SondeInfo *si = sonde.si();
|
SondeData *si = &(sonde.si()->d);
|
||||||
|
|
||||||
int32_t corr = reedsolomon41(data, 560, 131); // try short frame first
|
int32_t corr = reedsolomon41(data, 560, 131); // try short frame first
|
||||||
if(corr<0) {
|
if(corr<0) {
|
||||||
|
@ -680,6 +680,12 @@ int RS41::decode41(byte *data, int maxlen)
|
||||||
switch(typ) {
|
switch(typ) {
|
||||||
case 'y': // name
|
case 'y': // name
|
||||||
{
|
{
|
||||||
|
if(strncmp(si->id, (const char *)(data+p+2), 8)) {
|
||||||
|
// ID changed, i.e. new sonde on same frequency. clear calibration and all other data
|
||||||
|
sonde.clearAllData(sonde.si());
|
||||||
|
struct subframeBuffer *sub = (struct subframeBuffer *)sonde.si()->extra;
|
||||||
|
if(sub) { sub->valid = 0; }
|
||||||
|
}
|
||||||
Serial.print("#");
|
Serial.print("#");
|
||||||
uint16_t fnr = data[p]+(data[p+1]<<8);
|
uint16_t fnr = data[p]+(data[p+1]<<8);
|
||||||
Serial.print(fnr);
|
Serial.print(fnr);
|
||||||
|
@ -687,13 +693,8 @@ int RS41::decode41(byte *data, int maxlen)
|
||||||
Serial.print("; RS41 ID ");
|
Serial.print("; RS41 ID ");
|
||||||
snprintf(buf, 10, "%.8s ", data+p+2);
|
snprintf(buf, 10, "%.8s ", data+p+2);
|
||||||
Serial.print(buf);
|
Serial.print(buf);
|
||||||
sonde.si()->batteryVoltage = data[p+10] / 10.0f;
|
si->batteryVoltage = data[p+10] / 10.0f;
|
||||||
si->type=STYPE_RS41;
|
// not needed, if we end up here, the type has to be RS41.... si->type=STYPE_RS41;
|
||||||
if(strncmp(si->id, (const char *)(data+p+2), 8)) {
|
|
||||||
// ID changed, i.e. new sonde on same frequency. clear calibration data
|
|
||||||
struct subframeBuffer *sub = (struct subframeBuffer *)si->extra;
|
|
||||||
if(sub) { sub->valid = 0; }
|
|
||||||
}
|
|
||||||
strncpy(si->id, (const char *)(data+p+2), 8);
|
strncpy(si->id, (const char *)(data+p+2), 8);
|
||||||
si->id[8]=0;
|
si->id[8]=0;
|
||||||
strncpy(si->ser, (const char *)(data+p+2), 8);
|
strncpy(si->ser, (const char *)(data+p+2), 8);
|
||||||
|
@ -761,7 +762,7 @@ int RS41::decode41(byte *data, int maxlen)
|
||||||
Serial.printf( "Humid sensor: tempHumiMain = %ld, tempHumiRef1 = %ld, tempHumiRef2 = %ld\n", tempHumiMain, tempHumiRef1, tempHumiRef2 );
|
Serial.printf( "Humid sensor: tempHumiMain = %ld, tempHumiRef1 = %ld, tempHumiRef2 = %ld\n", tempHumiMain, tempHumiRef1, tempHumiRef2 );
|
||||||
Serial.printf( "Pressure sens: pressureMain = %ld, pressureRef1 = %ld, pressureRef2 = %ld\n", pressureMain, pressureRef1, pressureRef2 );
|
Serial.printf( "Pressure sens: pressureMain = %ld, pressureRef1 = %ld, pressureRef2 = %ld\n", pressureMain, pressureRef1, pressureRef2 );
|
||||||
#endif
|
#endif
|
||||||
struct subframeBuffer *calibration = (struct subframeBuffer *)si->extra;
|
struct subframeBuffer *calibration = (struct subframeBuffer *)(sonde.si()->extra);
|
||||||
// check for bits 3 through 20 set and 37 through 46
|
// check for bits 3 through 20 set and 37 through 46
|
||||||
bool validExternalTemperature = calibration!=NULL && (calibration->valid & 0xF8) == 0xF8;
|
bool validExternalTemperature = calibration!=NULL && (calibration->valid & 0xF8) == 0xF8;
|
||||||
bool validHumidity = calibration!=NULL && (calibration->valid & 0x7FE0001FFFF8) == 0x7FE0001FFFF8;
|
bool validHumidity = calibration!=NULL && (calibration->valid & 0x7FE0001FFFF8) == 0x7FE0001FFFF8;
|
||||||
|
|
|
@ -552,7 +552,7 @@ int RS92::waitRXcomplete() {
|
||||||
Serial.printf("decoding frame %d\n", lastFrame);
|
Serial.printf("decoding frame %d\n", lastFrame);
|
||||||
print_frame(lastFrame==1?data1:data2, 240);
|
print_frame(lastFrame==1?data1:data2, 240);
|
||||||
|
|
||||||
SondeInfo *si = sonde.sondeList+rxtask.receiveSonde;
|
SondeData *si = &( (sonde.sondeList+rxtask.receiveSonde)->d );
|
||||||
si->lat = gpx.lat;
|
si->lat = gpx.lat;
|
||||||
si->lon = gpx.lon;
|
si->lon = gpx.lon;
|
||||||
si->alt = gpx.alt;
|
si->alt = gpx.alt;
|
||||||
|
|
|
@ -65,7 +65,7 @@ void ShFreqImport::populate(char *id, float lat, float lon, float freq, const ch
|
||||||
// update label if its a dynamic SH entry
|
// update label if its a dynamic SH entry
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<sonde.config.maxsonde; i++) {
|
for(i=0; i<sonde.config.maxsonde; i++) {
|
||||||
if( abs(sonde.sondeList[i].freq-freq)<0.0015 ) { // exists already, max error 1500 Hz
|
if( abs(sonde.sondeList[i].freq-freq)<0.003 ) { // exists already, max error 3000 Hz
|
||||||
Serial.printf("id %s close to %d\n", id, i);
|
Serial.printf("id %s close to %d\n", id, i);
|
||||||
if( sonde.sondeList[i].type == stype) {
|
if( sonde.sondeList[i].type == stype) {
|
||||||
char *l = sonde.sondeList[i].launchsite;
|
char *l = sonde.sondeList[i].launchsite;
|
||||||
|
@ -103,6 +103,8 @@ void ShFreqImport::cleanup() {
|
||||||
//Serial.println("Cleanup called ********");
|
//Serial.println("Cleanup called ********");
|
||||||
for(int i=0; i<sonde.config.maxsonde; i++) {
|
for(int i=0; i<sonde.config.maxsonde; i++) {
|
||||||
if( (((inuse[i/8]>>(i&7))&1) == 0) && *sonde.sondeList[i].launchsite=='@' ) {
|
if( (((inuse[i/8]>>(i&7))&1) == 0) && *sonde.sondeList[i].launchsite=='@' ) {
|
||||||
|
// Don't remove the currently active entry
|
||||||
|
if(i==sonde.currentSonde) continue;
|
||||||
Serial.printf("removing #%d\n", i);
|
Serial.printf("removing #%d\n", i);
|
||||||
sonde.sondeList[i].launchsite[0] = 0;
|
sonde.sondeList[i].launchsite[0] = 0;
|
||||||
sonde.sondeList[i].active = 0;
|
sonde.sondeList[i].active = 0;
|
||||||
|
|
|
@ -362,9 +362,10 @@ void Sonde::addSonde(float frequency, SondeType type, int active, char *launchsi
|
||||||
if(sondeList[nSonde].extra) free(sondeList[nSonde].extra);
|
if(sondeList[nSonde].extra) free(sondeList[nSonde].extra);
|
||||||
memset(&sondeList[nSonde], 0, sizeof(SondeInfo));
|
memset(&sondeList[nSonde], 0, sizeof(SondeInfo));
|
||||||
sondeList[nSonde].type = type;
|
sondeList[nSonde].type = type;
|
||||||
sondeList[nSonde].typestr[0] = 0;
|
sondeList[nSonde].d.typestr[0] = 0;
|
||||||
sondeList[nSonde].freq = frequency;
|
sondeList[nSonde].freq = frequency;
|
||||||
memcpy(sondeList[nSonde].rxStat, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", 18); // unknown/undefined
|
memcpy(sondeList[nSonde].rxStat, "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3", 18); // unknown/undefined
|
||||||
|
clearAllData(sondeList+nSonde);
|
||||||
}
|
}
|
||||||
sondeList[nSonde].active = active;
|
sondeList[nSonde].active = active;
|
||||||
strncpy(sondeList[nSonde].launchsite, launchsite, 17);
|
strncpy(sondeList[nSonde].launchsite, launchsite, 17);
|
||||||
|
@ -667,6 +668,14 @@ uint8_t Sonde::updateState(uint8_t event) {
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sonde::clearAllData(SondeInfo *si) {
|
||||||
|
// set everything to 0
|
||||||
|
memset(&(si->d), 0, sizeof(SondeData));
|
||||||
|
// set floats to NaN
|
||||||
|
si->d.lat = si->d.lon = si->d.alt = si->d.vs = si->d.hs = si->d.dir = NAN;
|
||||||
|
si->d.temperature = si->d.tempRHSensor = si->d.relativeHumidity = si->d.batteryVoltage = NAN;
|
||||||
|
}
|
||||||
|
|
||||||
void Sonde::updateDisplayPos() {
|
void Sonde::updateDisplayPos() {
|
||||||
disp.updateDisplayPos();
|
disp.updateDisplayPos();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,13 @@ extern uint8_t debug;
|
||||||
|
|
||||||
// RX_TIMEOUT: no header detected
|
// RX_TIMEOUT: no header detected
|
||||||
// RX_ERROR: header detected, but data not decoded (crc error, etc.)
|
// RX_ERROR: header detected, but data not decoded (crc error, etc.)
|
||||||
// RX_OK: header and data ok
|
// RX_PARTIAL: header detected, some data ok, some with errors
|
||||||
|
// For RS41: Some blocks with CRC error, some blocks ok in a single frame
|
||||||
|
// For DFM: In +- 1s, some but not all DAT-subframes 1,2,3,4,5,6,7,8 received
|
||||||
|
// For RS92 ??? unclear
|
||||||
|
// For M10/M20 its always all or nothing, no PARTIAL data
|
||||||
|
// For MP3H its alway all or nothing, no PARTIAL data
|
||||||
|
// RX_OK: header and all data ok
|
||||||
enum RxResult { RX_OK, RX_TIMEOUT, RX_ERROR, RX_UNKNOWN, RX_NOPOS };
|
enum RxResult { RX_OK, RX_TIMEOUT, RX_ERROR, RX_UNKNOWN, RX_NOPOS };
|
||||||
#define RX_UPDATERSSI 0xFFFE
|
#define RX_UPDATERSSI 0xFFFE
|
||||||
|
|
||||||
|
@ -68,18 +74,13 @@ extern const char *manufacturer_string[NSondeTypes];
|
||||||
#define TYPE_IS_DFM(t) ( (t)==STYPE_DFM )
|
#define TYPE_IS_DFM(t) ( (t)==STYPE_DFM )
|
||||||
#define TYPE_IS_METEO(t) ( (t)==STYPE_M10 || (t)==STYPE_M20 )
|
#define TYPE_IS_METEO(t) ( (t)==STYPE_M10 || (t)==STYPE_M20 )
|
||||||
|
|
||||||
typedef struct st_sondeinfo {
|
typedef struct st_sondedata {
|
||||||
// receiver configuration
|
|
||||||
bool active;
|
|
||||||
SondeType type;
|
|
||||||
int8_t subtype; /* 0 for none/unknown, hex type for dfm, 1/2 for M10/M20 */
|
|
||||||
float freq;
|
|
||||||
// decoded ID
|
// decoded ID
|
||||||
char typestr[5]; // decoded type (use type if *typestr==0)
|
|
||||||
char id[10];
|
char id[10];
|
||||||
char ser[12];
|
char ser[12];
|
||||||
bool validID;
|
bool validID;
|
||||||
char launchsite[18];
|
char typestr[5]; // decoded type (use type if *typestr==0)
|
||||||
|
int8_t subtype; /* 0 for none/unknown, hex type for dfm, 1/2 for M10/M20 */
|
||||||
// decoded position
|
// decoded position
|
||||||
float lat; // latitude
|
float lat; // latitude
|
||||||
float lon; // longitude
|
float lon; // longitude
|
||||||
|
@ -94,6 +95,25 @@ typedef struct st_sondeinfo {
|
||||||
uint32_t frame;
|
uint32_t frame;
|
||||||
uint32_t vframe; // vframe==frame if frame is unique/continous, otherweise vframe is derived from gps time
|
uint32_t vframe; // vframe==frame if frame is unique/continous, otherweise vframe is derived from gps time
|
||||||
bool validTime;
|
bool validTime;
|
||||||
|
// shut down timers, currently only for RS41; -1=disabled
|
||||||
|
uint16_t launchKT, burstKT, countKT;
|
||||||
|
uint16_t crefKT; // frame number in which countKT was last sent
|
||||||
|
// sonde specific extra data, NULL if unused or not yet initialized, currently used for RS41 subframe data (calibration)
|
||||||
|
float temperature = -300.0; // platinum resistor temperature
|
||||||
|
float tempRHSensor = -300.0; // temperature of relative humidity sensor
|
||||||
|
float relativeHumidity = -1.0; // relative humidity
|
||||||
|
float batteryVoltage = -1;
|
||||||
|
} SondeData;
|
||||||
|
|
||||||
|
typedef struct st_sondeinfo {
|
||||||
|
// First part: static configuration, not decoded data.
|
||||||
|
// receiver configuration
|
||||||
|
bool active;
|
||||||
|
SondeType type;
|
||||||
|
float freq;
|
||||||
|
char launchsite[18];
|
||||||
|
|
||||||
|
// Second part: internal decoder state. no need to clear this on new sonde
|
||||||
// RSSI from receiver
|
// RSSI from receiver
|
||||||
int rssi; // signal strength
|
int rssi; // signal strength
|
||||||
int32_t afc; // afc correction value
|
int32_t afc; // afc correction value
|
||||||
|
@ -103,15 +123,12 @@ typedef struct st_sondeinfo {
|
||||||
uint32_t norxStart; // millis() timestamp of continuous no rx start
|
uint32_t norxStart; // millis() timestamp of continuous no rx start
|
||||||
uint32_t viewStart; // millis() timestamp of viewinf this sonde with current display
|
uint32_t viewStart; // millis() timestamp of viewinf this sonde with current display
|
||||||
int8_t lastState; // -1: disabled; 0: norx; 1: rx
|
int8_t lastState; // -1: disabled; 0: norx; 1: rx
|
||||||
// shut down timers, currently only for RS41; -1=disabled
|
|
||||||
uint16_t launchKT, burstKT, countKT;
|
// Third part: decoded data. Clear if reception of a new sonde has started
|
||||||
uint16_t crefKT; // frame number in which countKT was last sent
|
SondeData d;
|
||||||
// sonde specific extra data, NULL if unused or not yet initialized, currently used for RS41 subframe data (calibration)
|
|
||||||
|
// Decoder-specific data, dynamically allocated (for RS41: calibration data)
|
||||||
void *extra;
|
void *extra;
|
||||||
float temperature = -300.0; // platinum resistor temperature
|
|
||||||
float tempRHSensor = -300.0; // temperature of relative humidity sensor
|
|
||||||
float relativeHumidity = -1.0; // relative humidity
|
|
||||||
float batteryVoltage = -1;
|
|
||||||
} SondeInfo;
|
} SondeInfo;
|
||||||
// rxStat: 3=undef[empty] 1=timeout[.] 2=errro[E] 0=ok[|] 4=no valid position[°]
|
// rxStat: 3=undef[empty] 1=timeout[.] 2=errro[E] 0=ok[|] 4=no valid position[°]
|
||||||
|
|
||||||
|
@ -319,6 +336,7 @@ public:
|
||||||
uint16_t waitRXcomplete();
|
uint16_t waitRXcomplete();
|
||||||
|
|
||||||
SondeInfo *si();
|
SondeInfo *si();
|
||||||
|
void clearAllData(SondeInfo *si);
|
||||||
|
|
||||||
uint8_t timeoutEvent(SondeInfo *si);
|
uint8_t timeoutEvent(SondeInfo *si);
|
||||||
uint8_t updateState(uint8_t event);
|
uint8_t updateState(uint8_t event);
|
||||||
|
|
|
@ -258,8 +258,9 @@ static uint32_t dao91(double x)
|
||||||
char b[201];
|
char b[201];
|
||||||
//char raw[201];
|
//char raw[201];
|
||||||
|
|
||||||
char *aprs_senddata(SondeInfo *s, const char *usercall, const char *sym) {
|
char *aprs_senddata(SondeInfo *si, const char *usercall, const char *sym) {
|
||||||
// float lat, float lon, float alt, float speed, float dir, float climb, const char *type, const char *objname, const char *usercall, const char *sym, const char *comm)
|
// float lat, float lon, float alt, float speed, float dir, float climb, const char *type, const char *objname, const char *usercall, const char *sym, const char *comm)
|
||||||
|
SondeData *s = &(si->d);
|
||||||
*b=0;
|
*b=0;
|
||||||
aprsstr_append(b, usercall);
|
aprsstr_append(b, usercall);
|
||||||
aprsstr_append(b, ">");
|
aprsstr_append(b, ">");
|
||||||
|
@ -299,9 +300,9 @@ char *aprs_senddata(SondeInfo *s, const char *usercall, const char *sym) {
|
||||||
|
|
||||||
strcat(b, "&");
|
strcat(b, "&");
|
||||||
char comm[100];
|
char comm[100];
|
||||||
snprintf(comm, 100, "Clb=%.1fm/s %.3fMHz Type=%s", s->vs, s->freq, sondeTypeStr[s->type]);
|
snprintf(comm, 100, "Clb=%.1fm/s %.3fMHz Type=%s", s->vs, si->freq, sondeTypeStr[si->type]);
|
||||||
strcat(b, comm);
|
strcat(b, comm);
|
||||||
if( TYPE_IS_DFM(s->type) || TYPE_IS_METEO(s->type) ) {
|
if( TYPE_IS_DFM(si->type) || TYPE_IS_METEO(si->type) ) {
|
||||||
snprintf(comm, 100, " ser=%s", s->ser);
|
snprintf(comm, 100, " ser=%s", s->ser);
|
||||||
strcat(b, comm);
|
strcat(b, comm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,8 +51,9 @@ void MQTT::publishUptime()
|
||||||
mqttClient.publish(topic, 1, 1, payload);
|
mqttClient.publish(topic, 1, 1, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MQTT::publishPacket(SondeInfo *s)
|
void MQTT::publishPacket(SondeInfo *si)
|
||||||
{
|
{
|
||||||
|
SondeData *s = &(si->d);
|
||||||
mqttClient.connect(); // ensure we've got connection
|
mqttClient.connect(); // ensure we've got connection
|
||||||
|
|
||||||
char payload[1024];
|
char payload[1024];
|
||||||
|
@ -86,12 +87,12 @@ void MQTT::publishPacket(SondeInfo *s)
|
||||||
"\"countKT\": %d,"
|
"\"countKT\": %d,"
|
||||||
"\"crefKT\": %d"
|
"\"crefKT\": %d"
|
||||||
"}",
|
"}",
|
||||||
(int)s->active,
|
(int)si->active,
|
||||||
s->freq,
|
si->freq,
|
||||||
s->id,
|
s->id,
|
||||||
s->ser,
|
s->ser,
|
||||||
(int)s->validID,
|
(int)s->validID,
|
||||||
s->launchsite,
|
si->launchsite,
|
||||||
s->lat,
|
s->lat,
|
||||||
s->lon,
|
s->lon,
|
||||||
s->alt,
|
s->alt,
|
||||||
|
@ -103,13 +104,13 @@ void MQTT::publishPacket(SondeInfo *s)
|
||||||
s->time,
|
s->time,
|
||||||
s->frame,
|
s->frame,
|
||||||
(int)s->validTime,
|
(int)s->validTime,
|
||||||
s->rssi,
|
si->rssi,
|
||||||
s->afc,
|
si->afc,
|
||||||
s->rxStat,
|
si->rxStat,
|
||||||
s->rxStart,
|
si->rxStart,
|
||||||
s->norxStart,
|
si->norxStart,
|
||||||
s->viewStart,
|
si->viewStart,
|
||||||
s->lastState,
|
si->lastState,
|
||||||
s->launchKT,
|
s->launchKT,
|
||||||
s->burstKT,
|
s->burstKT,
|
||||||
s->countKT,
|
s->countKT,
|
||||||
|
|
Ładowanie…
Reference in New Issue