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

@ -338,13 +338,15 @@ void addSondeStatus(char *ptr, int i)
struct tm ts; struct tm ts;
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</td></tr><tr><td>QTH: %.6f,%.6f h=%.0fm</td></tr>\n", sprintf(ptr + strlen(ptr), "<tr><td id=\"sfreq\">%3.3f MHz, Type: %s</td><tr><td>ID: %s", s->freq, sondeTypeStr[s->type],
s->freq, sondeTypeStr[s->type], s->validID ? s->id : "<?""?>");
s->validID ? s->id : "<?""?>", if (s->validID && (s->type == STYPE_DFM06 || s->type == STYPE_DFM09 || s->type == STYPE_M10)) {
s->lat, s->lon, s->alt); 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; const time_t t = s->time;
ts = *gmtime(&t); ts = *gmtime(&t);
sprintf(ptr + strlen(ptr), "<tr><td>Frame# %d, Sats=%d, %04d-%02d-%02d %02d:%02d:%02d %d</td></tr>", 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); 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), "<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://wx.dl2mf.de/?%s\">WX.DL2MF.de</a> - ", s->id);
@ -1497,8 +1499,7 @@ void loopDecoder() {
// first check if ID and position lat+lonis ok // first check if ID and position lat+lonis ok
SondeInfo *s = &sonde.sondeList[rxtask.receiveSonde]; SondeInfo *s = &sonde.sondeList[rxtask.receiveSonde];
if (s->validID && ((s->validPos & 0x03) == 0x03)) { 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", const char *str = aprs_senddata(s, sonde.config.call, sonde.config.udpfeed.symbol);
sonde.config.udpfeed.symbol);
if (connected) { if (connected) {
char raw[201]; char raw[201];
int rawlen = aprsstr_mon2raw(str, raw, APRS_MAXLEN); int rawlen = aprsstr_mon2raw(str, raw, APRS_MAXLEN);

View File

@ -1,2 +1,2 @@
const char *version_name = "rdzTTGOsonde"; 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) { if(idgood==3) {
uint32_t dfmid = (highid<<16) | lowid; uint32_t dfmid = (highid<<16) | lowid;
Serial.print("DFM-09 ID: "); Serial.print(dfmid); 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; sonde.si()->validID = true;
} }
} }

View File

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

View File

@ -18,33 +18,10 @@
#endif #endif
#if 0 static byte data1[512];
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 *dataptr=data1; static byte *dataptr=data1;
static uint8_t rxbitc; static uint8_t rxbitc;
static int32_t asynst[10]={0};
static uint16_t rxbyte; static uint16_t rxbyte;
static int rxp=0; static int rxp=0;
static int haveNewFrame = 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)); 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) { static char hex(uint8_t nr) {
nr = nr&0x0f; nr = nr&0x0f;
if(nr<10) return '0'+nr; if(nr<10) return '0'+nr;
@ -294,6 +275,17 @@ bool M10::decodeframeM10(uint8_t *data) {
ids[8] = hex(id); ids[8] = hex(id);
ids[9] = 0; ids[9] = 0;
strncpy(sonde.si()->id, ids, 10); 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; sonde.si()->validID = true;
Serial.printf("ID is %s [%02x %02x %d]\n", ids, data[95], data[93], id); 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 // 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; sonde.si()->type=STYPE_RS41;
strncpy(sonde.si()->id, (const char *)(data+p+2), 8); strncpy(sonde.si()->id, (const char *)(data+p+2), 8);
sonde.si()->id[8]=0; sonde.si()->id[8]=0;
strncpy(sonde.si()->ser, (const char *)(data+p+2), 8);
sonde.si()->ser[8]=0;
sonde.si()->validID=true; sonde.si()->validID=true;
} }
// TODO: some more data // TODO: some more data

View File

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

View File

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

View File

@ -2,8 +2,6 @@
#ifndef Sonde_h #ifndef Sonde_h
#define Sonde_h #define Sonde_h
#include "aprs.h"
// 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_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 }; enum SondeType { STYPE_DFM06, STYPE_DFM09, STYPE_RS41, STYPE_RS92, STYPE_M10 };
extern const char *sondeTypeStr[NSondeTypes]; 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 // Used for interacting with the RX background task
typedef struct st_RXTask { typedef struct st_RXTask {
// Variables set by Arduino main loop to value >=0 for requesting // Variables set by Arduino main loop to value >=0 for requesting
@ -84,6 +118,29 @@ struct st_dfmconfig {
int rxbw; 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 { typedef struct st_rdzconfig {
// hardware configuration // hardware configuration
int button_pin; // PIN port number menu button (+128 for touch mode) int button_pin; // PIN port number menu button (+128 for touch mode)
@ -120,48 +177,13 @@ typedef struct st_rdzconfig {
struct st_dfmconfig dfm; struct st_dfmconfig dfm;
// data feed configuration // data feed configuration
// for now, one feed for each type is enough, but might get extended to more? // 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 char passcode[9]; // APRS passcode
struct st_feedinfo udpfeed; // target for AXUDP messages struct st_feedinfo udpfeed; // target for AXUDP messages
struct st_feedinfo tcpfeed; // target for APRS-IS TCP connections struct st_feedinfo tcpfeed; // target for APRS-IS TCP connections
struct st_kisstnc kisstnc; // target for KISS TNC (via TCP, mainly for APRSdroid) struct st_kisstnc kisstnc; // target for KISS TNC (via TCP, mainly for APRSdroid)
} RDZConfig; } 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 #define MAXSONDE 99

View File

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

View File

@ -1,34 +1,14 @@
#ifndef _aprs_h #ifndef _aprs_h
#define _aprs_h #define _aprs_h
#include "Sonde.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;
};
#define APRS_MAXLEN 201 #define APRS_MAXLEN 201
void aprs_gencrctab(void); void aprs_gencrctab(void);
int aprsstr_mon2raw(const char *mon, char raw[], int raw_len); int aprsstr_mon2raw(const char *mon, char raw[], int raw_len);
int aprsstr_mon2kiss(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 #endif