more info (frame#,sats) and time stamps from sonde in aprsmap data

This commit is contained in:
Hansi, dl9rdz 2019-11-02 13:18:17 +01:00
parent 08818e385e
commit de5308893a
11 changed files with 142 additions and 132 deletions

View File

@ -227,7 +227,7 @@ const char *handleQRGPost(AsyncWebServerRequest *request) {
const char *tstr = tstring.c_str();
const char *sstr = sstring.c_str();
Serial.printf("Processing a=%s, f=%s, t=%s, site=%s\n", active ? "YES" : "NO", fstr, tstr, sstr);
char typech = (tstr[2] == '4' ? '4' : tstr[2] == '9' ? 'R' : tstr[0]=='M' ? 'M' : tstr[3]); // a bit ugly
char typech = (tstr[2] == '4' ? '4' : tstr[2] == '9' ? 'R' : tstr[0] == 'M' ? 'M' : tstr[3]); // a bit ugly
file.printf("%3.3f %c %c %s\n", atof(fstr), typech, active ? '+' : '-', sstr);
}
file.close();
@ -338,14 +338,16 @@ void addSondeStatus(char *ptr, int i)
struct tm ts;
SondeInfo *s = &sonde.sondeList[i];
strcat(ptr, "<table>");
sprintf(ptr + strlen(ptr), "<tr><td id=\"sfreq\">%3.3f MHz, Type: %s</td><tr><td>ID: %s</td></tr><tr><td>QTH: %.6f,%.6f h=%.0fm</td></tr>\n",
s->freq, sondeTypeStr[s->type],
s->validID ? s->id : "<?""?>",
s->lat, s->lon, s->alt);
sprintf(ptr + strlen(ptr), "<tr><td id=\"sfreq\">%3.3f MHz, Type: %s</td><tr><td>ID: %s", s->freq, sondeTypeStr[s->type],
s->validID ? s->id : "<?""?>");
if (s->validID && (s->type == STYPE_DFM06 || s->type == STYPE_DFM09 || s->type == STYPE_M10)) {
sprintf(ptr + strlen(ptr), " (ser: %s)", s->ser);
}
sprintf(ptr + strlen(ptr), "</td></tr><tr><td>QTH: %.6f,%.6f h=%.0fm</td></tr>\n", s->lat, s->lon, s->alt);
const time_t t = s->time;
ts = *gmtime(&t);
sprintf(ptr + strlen(ptr), "<tr><td>Frame# %d, Sats=%d, %04d-%02d-%02d %02d:%02d:%02d %d</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->sec);
sprintf(ptr + strlen(ptr), "<tr><td>Frame# %d, 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->sec);
sprintf(ptr + strlen(ptr), "<tr><td><a target=\"_empty\" href=\"geo:%.6f,%.6f\">GEO-App</a> - ", s->lat, s->lon);
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://wx.dl2mf.de/?%s\">WX.DL2MF.de</a> - ", s->id);
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://www.openstreetmap.org/?mlat=%.6f&mlon=%.6f&zoom=14\">OSM</a></td></tr>", s->lat, s->lon);
@ -1497,8 +1499,7 @@ void loopDecoder() {
// first check if ID and position lat+lonis ok
SondeInfo *s = &sonde.sondeList[rxtask.receiveSonde];
if (s->validID && ((s->validPos & 0x03) == 0x03)) {
const char *str = aprs_senddata(s->lat, s->lon, s->alt, s->hs, s->dir, s->vs, sondeTypeStr[s->type], s->id, "TE0ST",
sonde.config.udpfeed.symbol);
const char *str = aprs_senddata(s, sonde.config.call, sonde.config.udpfeed.symbol);
if (connected) {
char raw[201];
int rawlen = aprsstr_mon2raw(str, raw, APRS_MAXLEN);

View File

@ -1,2 +1,2 @@
const char *version_name = "rdzTTGOsonde";
const char *version_id = "devel20191101";
const char *version_id = "devel20191102";

View File

@ -183,7 +183,9 @@ void DFM::decodeCFG(uint8_t *cfg)
if(idgood==3) {
uint32_t dfmid = (highid<<16) | lowid;
Serial.print("DFM-09 ID: "); Serial.print(dfmid);
snprintf(sonde.si()->id, 10, "%d", dfmid);
snprintf(sonde.si()->ser, 10, "%d", dfmid);
// dxlAPRS sonde number (DF6 (why??) and 5 last digits of serial number as hex number
snprintf(sonde.si()->id, 9, "DF6%05X", dfmid&0xfffff);
sonde.si()->validID = true;
}
}

View File

@ -24,7 +24,7 @@ extern bool axp192_found;
SPIClass spiDisp(HSPI);
const char *sondeTypeStr[NSondeTypes] = { "DFM6", "DFM9", "RS41", "RS92", "M10 " };
const char *sondeTypeStr[NSondeTypes] = { "DFM6", "DFM9", "RS41", "RS92", "M10" };
byte myIP_tiles[8*11];
static uint8_t ap_tile[8]={0x00,0x04,0x22,0x92, 0x92, 0x22, 0x04, 0x00};
@ -256,7 +256,7 @@ void U8x8Display::welcome() {
drawString(8 - strlen(version_name) / 2, 0, version_name);
drawString(8 - strlen(version_id) / 2, 2, version_id);
setFont(FONT_SMALL);
drawString(0, 4, "RS41,RS92,DFM6/9");
drawString(0, 4, "RS41/92,DFM,M10");
drawString(0, 6, "by Hansi, DL9RDZ");
}
@ -427,10 +427,10 @@ void ILI9225Display::welcome() {
setFont(5);
int l=3*22;
if(sonde.config.tft_orient&1) {
drawString(0, 1*22, "RS41,RS92,DFM6/9");
drawString(0, 1*22, "RS41/92,DFM6/9,M10");
} else {
drawString(0, 1*22, "RS41,RS92,");
drawString(0, 2*22, "DFM6/9");
drawString(0, 2*22, "DFM6/9,M10");
l+=22;
}
drawString(0, l, version_id);
@ -945,18 +945,21 @@ void Display::drawID(DispEntry *de) {
if(!de->extra || de->extra[0]=='s') {
// real serial number, as printed on sonde
drawString(de, sonde.si()->id);
drawString(de, sonde.si()->ser);
} else if (de->extra[0]=='a') {
// autorx sonde number ("DF9" and last 6 digits of real serial number
strcpy(buf, sonde.si()->id);
// autorx sonde number ("DF9" and last 6 digits of real serial number)
if(sonde.si()->type == STYPE_DFM09) {
int n = strlen(sonde.si()->ser) - 6;
if(n<0) n=0;
memcpy(buf, "DF9", 3);
memcpy(buf+3, sonde.si()->ser+n, 6);
drawString(de, buf);
} else {
drawString(de, sonde.si()->ser);
}
} else {
// dxlAPRS sonde number (DF6 (why??) and 5 last digits of serial number as hex number
uint32_t id = atoi(sonde.si()->id);
id = id&0xfffff;
snprintf(buf, 16, "DF6%05X", id);
drawString(de, buf);
drawString(de, sonde.si()->id);
}
}
void Display::drawRSSI(DispEntry *de) {

View File

@ -18,33 +18,10 @@
#endif
#if 0
static double atang2(double x, double y)
{
double w;
if (fabs(x)>fabs(y)) {
w = (double)atan((float)(X2C_DIVL(y,x)));
if (x<0.0) {
if (y>0.0) w = 3.1415926535898+w;
else w = w-3.1415926535898;
}
}
else if (y!=0.0) {
w = (double)(1.5707963267949f-atan((float)(X2C_DIVL(x,
y))));
if (y<0.0) w = w-3.1415926535898;
}
else w = 0.0;
return w;
} /* end atang2() */
#endif
static byte data1[512]={0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x10};
static byte data2[512]={0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x10};
static byte data1[512];
static byte *dataptr=data1;
static uint8_t rxbitc;
static int32_t asynst[10]={0};
static uint16_t rxbyte;
static int rxp=0;
static int haveNewFrame = 0;
@ -239,6 +216,10 @@ static int16_t getint16(uint8_t *data) {
return (int16_t)(data[1]|((uint16_t)data[0]<<8));
}
static char dez(uint8_t nr) {
nr = nr%10;
return '0'+nr;
}
static char hex(uint8_t nr) {
nr = nr&0x0f;
if(nr<10) return '0'+nr;
@ -294,6 +275,17 @@ bool M10::decodeframeM10(uint8_t *data) {
ids[8] = hex(id);
ids[9] = 0;
strncpy(sonde.si()->id, ids, 10);
ids[0] = hex(data[95]/16);
ids[1] = dez((data[95]&0x0f)/10);
ids[2] = dez((data[95]&0x0f));
ids[3] = dez(data[93]);
ids[4] = dez(id>>13);
id &= 0x1fff;
ids[5] = dez(id/1000);
ids[6] = dez((id/100)%10);
ids[7] = dez((id/10)%10);
ids[8] = dez(id%10);
strncpy(sonde.si()->ser, ids, 10);
sonde.si()->validID = true;
Serial.printf("ID is %s [%02x %02x %d]\n", ids, data[95], data[93], id);
// ID printed on sonde is ...-.-abbbb, with a=id>>13, bbbb=id&0x1fff in decimal

View File

@ -427,6 +427,8 @@ int RS41::decode41(byte *data, int maxlen)
sonde.si()->type=STYPE_RS41;
strncpy(sonde.si()->id, (const char *)(data+p+2), 8);
sonde.si()->id[8]=0;
strncpy(sonde.si()->ser, (const char *)(data+p+2), 8);
sonde.si()->ser[8]=0;
sonde.si()->validID=true;
}
// TODO: some more data

View File

@ -622,6 +622,7 @@ int RS92::waitRXcomplete() {
si->dir = gpx.vD;
si->validPos = 0x3f;
memcpy(si->id, gpx.id, 9);
memcpy(si->ser, gpx.id, 9);
si->validID = true;
si->frame = gpx.frnr;
si->sats = gpx.k;

View File

@ -70,6 +70,7 @@ void Sonde::defaultConfig() {
config.touch_thresh = 70;
config.led_pout = 9;
config.power_pout = -1;
config.spectrum=10;
// Try autodetecting board type
// Seems like on startup, GPIO4 is 1 on v1 boards, 0 on v2.1 boards?
config.gps_rxd = -1;
@ -112,6 +113,7 @@ void Sonde::defaultConfig() {
config.oled_rst = 14;
config.tft_rs = 2;
config.tft_cs = 0;
config.spectrum = -1; // no spectrum for now on large display
} else {
// OLED display, pins 21,22 ok...
config.disptype = 0;
@ -131,6 +133,7 @@ void Sonde::defaultConfig() {
config.oled_rst = 22;
config.tft_rs = 2;
config.tft_cs = 0;
config.spectrum = -1; // no spectrum for now on large display
}
}
} else {
@ -151,7 +154,6 @@ void Sonde::defaultConfig() {
config.display[2]=-1;
config.startfreq=400;
config.channelbw=10;
config.spectrum=10;
config.marker=0;
config.showafc=0;
config.freqofs=0;
@ -191,6 +193,7 @@ void Sonde::setConfig(const char *cfg) {
if(config.noisefloor==0) config.noisefloor=-130;
} else if(strcmp(cfg,"call")==0) {
strncpy(config.call, val, 9);
config.call[9]=0;
} else if(strcmp(cfg,"passcode")==0) {
strncpy(config.passcode, val, 9);
} else if(strcmp(cfg,"button_pin")==0) {

View File

@ -2,8 +2,6 @@
#ifndef Sonde_h
#define Sonde_h
#include "aprs.h"
// RX_TIMEOUT: no header detected
// RX_ERROR: header detected, but data not decoded (crc error, etc.)
// RX_OK: header and data ok
@ -51,6 +49,42 @@ extern const char *RXstr[];
enum SondeType { STYPE_DFM06, STYPE_DFM09, STYPE_RS41, STYPE_RS92, STYPE_M10 };
extern const char *sondeTypeStr[NSondeTypes];
typedef struct st_sondeinfo {
// receiver configuration
bool active;
SondeType type;
float freq;
// decoded ID
char id[10];
char ser[12];
bool validID;
char launchsite[18];
// decoded position
float lat; // latitude
float lon; // longitude
float alt; // altitude
float vs; // vertical speed
float hs; // horizontal speed
float dir; // 0..360
uint8_t sats; // number of sats
uint8_t validPos; // bit pattern for validity of above 6 fields
// decoded GPS time
uint32_t time;
uint16_t sec;
uint32_t frame;
bool validTime;
// RSSI from receiver
int rssi; // signal strength
int32_t afc; // afc correction value
// statistics
uint8_t rxStat[20];
uint32_t rxStart; // millis() timestamp of continuous rx start
uint32_t norxStart; // millis() timestamp of continuous no rx start
uint32_t viewStart; // millis() timestamp of viewinf this sonde with current display
int8_t lastState; // -1: disabled; 0: norx; 1: rx
} SondeInfo;
// rxStat: 3=undef[empty] 1=timeout[.] 2=errro[E] 3=ok[1] 5=no valid position[°]
// Used for interacting with the RX background task
typedef struct st_RXTask {
// Variables set by Arduino main loop to value >=0 for requesting
@ -84,6 +118,29 @@ struct st_dfmconfig {
int rxbw;
};
enum IDTYPE { ID_DFMDXL, ID_DFMGRAW, ID_DFMAUTO };
struct st_feedinfo {
bool active;
int type; // 0:UDP(axudp), 1:TCP(aprs.fi)
char host[64];
int port;
char symbol[3];
int lowrate;
int highrate;
int lowlimit;
int idformat; // 0: dxl 1: real 2: auto
};
// maybe extend for external Bluetooth interface?
// internal bluetooth consumes too much memory
struct st_kisstnc {
bool active;
int idformat;
};
typedef struct st_rdzconfig {
// hardware configuration
int button_pin; // PIN port number menu button (+128 for touch mode)
@ -120,48 +177,13 @@ typedef struct st_rdzconfig {
struct st_dfmconfig dfm;
// data feed configuration
// for now, one feed for each type is enough, but might get extended to more?
char call[9]; // APRS callsign
char call[10]; // APRS callsign
char passcode[9]; // APRS passcode
struct st_feedinfo udpfeed; // target for AXUDP messages
struct st_feedinfo tcpfeed; // target for APRS-IS TCP connections
struct st_kisstnc kisstnc; // target for KISS TNC (via TCP, mainly for APRSdroid)
} RDZConfig;
typedef struct st_sondeinfo {
// receiver configuration
bool active;
SondeType type;
float freq;
// decoded ID
char id[10];
bool validID;
char launchsite[18];
// decoded position
float lat; // latitude
float lon; // longitude
float alt; // altitude
float vs; // vertical speed
float hs; // horizontal speed
float dir; // 0..360
uint8_t sats; // number of sats
uint8_t validPos; // bit pattern for validity of above 6 fields
// decoded GPS time
uint32_t time;
uint16_t sec;
uint32_t frame;
bool validTime;
// RSSI from receiver
int rssi; // signal strength
int32_t afc; // afc correction value
// statistics
uint8_t rxStat[20];
uint32_t rxStart; // millis() timestamp of continuous rx start
uint32_t norxStart; // millis() timestamp of continuous no rx start
uint32_t viewStart; // millis() timestamp of viewinf this sonde with current display
int8_t lastState; // -1: disabled; 0: norx; 1: rx
} SondeInfo;
// rxStat: 3=undef[empty] 1=timeout[.] 2=errro[E] 3=ok[1] 5=no valid position[°]
#define MAXSONDE 99

View File

@ -8,7 +8,7 @@
*/
#include <stdio.h>
#include <string.h>
#include <WString.h>
#include <stdlib.h>
//#include <arpa/inet.h>
//#include <sys/socket.h>
@ -274,8 +274,8 @@ static uint32_t dao91(double x)
char b[201];
char raw[201];
char * aprs_senddata(float lat, float lon, float alt, float speed, float dir, float climb, const char *type, const char *objname, const char *usercall, const char *sym)
{
char *aprs_senddata(SondeInfo *s, 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)
*b=0;
aprsstr_append(b, usercall);
aprsstr_append(b, ">");
@ -284,39 +284,43 @@ char * aprs_senddata(float lat, float lon, float alt, float speed, float dir, fl
// uncompressed
aprsstr_append(b, ":;");
char tmp[10];
snprintf(tmp,10,"%s ",objname);
snprintf(tmp,10,"%s ",s->id);
aprsstr_append(b, tmp);
aprsstr_append(b, "*");
// TODO: time
//aprsstr_append_data(time, ds);
aprsstr_append(b, "121212z");
// time
int i = strlen(b);
int lati = abs((int)lat);
int latm = (fabs(lat)-lati)*6000;
snprintf(b+i, APRS_MAXLEN-i, "%02d%02d.%02d%c%c", lati, latm/100, latm%100, lat<0?'S':'N', sym[0]);
int sec = s->time % 86400;
snprintf(b+i, APRS_MAXLEN-1, "%02d%02d%02dz", sec/(60*60), (sec%(60*60))/60, sec%60);
i = strlen(b);
int loni = abs((int)lon);
int lonm = (fabs(lon)-loni)*6000;
snprintf(b+i, APRS_MAXLEN-i, "%03d%02d.%02d%c%c", loni, lonm/100, lonm%100, lon<0?'W':'E', sym[1]);
#if 1
if(speed>0.5) {
//aprsstr_append_data(time, ds);
int lati = abs((int)s->lat);
int latm = (fabs(s->lat)-lati)*6000;
snprintf(b+i, APRS_MAXLEN-i, "%02d%02d.%02d%c%c", lati, latm/100, latm%100, s->lat<0?'S':'N', sym[0]);
i = strlen(b);
int loni = abs((int)s->lon);
int lonm = (fabs(s->lon)-loni)*6000;
snprintf(b+i, APRS_MAXLEN-i, "%03d%02d.%02d%c%c", loni, lonm/100, lonm%100, s->lon<0?'W':'E', sym[1]);
if(s->hs>0.5) {
i=strlen(b);
snprintf(b+i, APRS_MAXLEN-i, "%03d/%03d", realcard(dir+1.5), realcard(speed*1.0/KNOTS+0.5));
snprintf(b+i, APRS_MAXLEN-i, "%03d/%03d", realcard(s->dir+1.5), realcard(s->hs*1.0/KNOTS+0.5));
}
#endif
if(alt>0.5) {
if(s->alt>0.5) {
i=strlen(b);
snprintf(b+i, APRS_MAXLEN-i, "/A=%06d", realcard(alt*FEET+0.5));
snprintf(b+i, APRS_MAXLEN-i, "/A=%06d", realcard(s->alt*FEET+0.5));
}
#if 1
int dao=1;
if(dao) {
i=strlen(b);
snprintf(b+i, APRS_MAXLEN-i, "!w%c%c!", 33+dao91(lat), 33+dao91(lon));
snprintf(b+i, APRS_MAXLEN-i, "!w%c%c!", 33+dao91(s->lat), 33+dao91(s->lon));
}
#endif
const char *comm="&test";
strcat(b, "&");
char comm[100];
snprintf(comm, 100, "Clb=%.1fm/s %.3fMHz Type=%s", s->vs, s->freq, sondeTypeStr[s->type]);
strcat(b, comm);
if(s->type==STYPE_M10||s->type==STYPE_DFM06||s->type==STYPE_DFM09) {
snprintf(comm, 100, " ser=%s", s->ser);
strcat(b, comm);
}
return b;
}

View File

@ -1,34 +1,14 @@
#ifndef _aprs_h
#define _aprs_h
enum IDTYPE { ID_DFMDXL, ID_DFMGRAW, ID_DFMAUTO };
struct st_feedinfo {
bool active;
int type; // 0:UDP(axudp), 1:TCP(aprs.fi)
char host[64];
int port;
char symbol[3];
int lowrate;
int highrate;
int lowlimit;
int idformat; // 0: dxl 1: real 2: auto
};
// maybe extend for external Bluetooth interface?
// internal bluetooth consumes too much memory
struct st_kisstnc {
bool active;
int idformat;
};
#include "Sonde.h"
#define APRS_MAXLEN 201
void aprs_gencrctab(void);
int aprsstr_mon2raw(const char *mon, char raw[], int raw_len);
int aprsstr_mon2kiss(const char *mon, char raw[], int raw_len);
char * aprs_senddata(float lat, float lon, float alt, float speed, float dir, float climb, const char *type, const char *objname, const char *usercall, const char *sym);
char *aprs_senddata(SondeInfo *s, const char *usercall, const char *sym);
#endif