kopia lustrzana https://github.com/dl9rdz/rdz_ttgo_sonde
Merge branch 'dl9rdz:devel' into devel
commit
70ee641ec1
|
@ -4,7 +4,7 @@ rdzTTGOsonde
|
|||
This a decoder for radiosonde RS41, RS92, DFM06/09/17, M10/M20, and MP3H
|
||||
based on a TTGO LoRa ESP32 board.
|
||||
|
||||
It supports OLED displays (SSD1306, SH1106) and TFT displays (ILI9225).
|
||||
It supports OLED displays (SSD1306, SH1106) and TFT displays (ILI9225, ILI9341/9342).
|
||||
|
||||
It also supports feeding data to external applications using WiFi (NOT bluetooth):
|
||||
- Arduino app by dl9rdz (see https://github.com/dl9rdz/rdzwx-go for apk download)
|
||||
|
|
|
@ -68,7 +68,7 @@ var cfgs = [
|
|||
[ "", "SondeHub frequency import", "https://github.com/dl9rdz/rdz_ttgo_sonde/wiki/SondeHub-import" ],
|
||||
[ "sondehub.fiactive", "SondeHub frequency import active (0=disabled, 1=active)" ],
|
||||
[ "sondehub.fiinterval", "Import frequency (minutes, ≥ 5)" ],
|
||||
[ "sondehub.fimaxdist", "Import maximum distance (km, ≤ 500)" ],
|
||||
[ "sondehub.fimaxdist", "Import maximum distance (km, ≤ 700)" ],
|
||||
[ "sondehub.fimaxage", "Import maximum age (hours, ≤ 48)" ],
|
||||
[ "", "Hardware configuration (requires reboot)", "https://github.com/dl9rdz/rdz_ttgo_sonde/wiki/Hardware-configuration"],
|
||||
[ "disptype", "Display type (0=OLED/SSD1306, 1=ILI9225, 2=OLED/SH1106, 3=ILI9341, 4=ILI9342)"],
|
||||
|
|
|
@ -234,7 +234,9 @@ fonts=0,1
|
|||
0,0=Is
|
||||
0,9=f
|
||||
1,12=t
|
||||
2,0=xTelemetry Data
|
||||
2,0=xSonde
|
||||
3,0=xData
|
||||
2,10=A
|
||||
4,0=Mt°C
|
||||
4,9=Mh%rH
|
||||
6,0=MphPa
|
||||
|
|
|
@ -14,6 +14,18 @@
|
|||
|
||||
#define DFM_FRAMELEN 33
|
||||
|
||||
|
||||
/*
|
||||
* observed DAT patterns for DFM-9:
|
||||
* A: 0+1; 2+3; 4+5; 6+7; 8+0 => keep frame in shadowFrame
|
||||
* B: 1+2; 3+4; 5+6; 7+8 => all good => keep date in shadowDate
|
||||
* C: 0+1; 2+3; 4+5; 6+7; 8+15 => all good => keep date in shadowDate
|
||||
* D: 0+1; 2+3; 4+5; 6+7; 0+1 => use shadowDate
|
||||
* not seen:5+6; 7+1
|
||||
* values:
|
||||
* 0:packet counter; 1:utc-msec; 2:lat,vh; 3:lon,dir, 4:alt,vv, 8=utc-date(day-hh-mm)
|
||||
*/
|
||||
|
||||
// single data structure, search restarts after decoder change
|
||||
static struct st_dfmstat {
|
||||
int idcnt0;
|
||||
|
@ -24,10 +36,14 @@ static struct st_dfmstat {
|
|||
uint16_t dat[50*2];
|
||||
uint8_t cnt[50*2];
|
||||
uint16_t good;
|
||||
uint32_t datesec;
|
||||
uint8_t frame;
|
||||
uint16_t msec;
|
||||
uint8_t nameregok;
|
||||
uint8_t nameregtop;
|
||||
uint8_t lastdat;
|
||||
uint8_t cycledone; // 0=no; 1=OK, 2=partially/with errors
|
||||
float meas[5+2];
|
||||
} dfmstate;
|
||||
|
||||
int DFM::setup(float frequency, int type)
|
||||
|
@ -160,7 +176,8 @@ int DFM::hamming(uint8_t *ham, int L, uint8_t *sym) {
|
|||
for (i = 0; i < L; i++) { // L bytes (4bit data, 4bit parity)
|
||||
if (use_ecc) {
|
||||
int res = check(ham+8*i);
|
||||
if(ret>=0 && res>=0) ret += res; else ret=-1;
|
||||
if( res<0 ) ret = -1;
|
||||
else if ( ret >= 0 && res > 0 ) ret++;
|
||||
}
|
||||
// systematic Hamming code: copy bits 0..3
|
||||
for (j = 0; j < 4; j++) {
|
||||
|
@ -323,14 +340,67 @@ void DFM::finddfname(uint8_t *b)
|
|||
}
|
||||
}
|
||||
|
||||
static float get_Temp() {
|
||||
SondeData *si = &(sonde.si()->d);
|
||||
if(!si->validID) { // type not yet known, so don't try to decode
|
||||
return NAN;
|
||||
}
|
||||
float f = dfmstate.meas[0],
|
||||
f1 = dfmstate.meas[3],
|
||||
f2 = dfmstate.meas[4];
|
||||
if(si->subtype >= 0x0C) {
|
||||
f = dfmstate.meas[1];
|
||||
f1 = dfmstate.meas[5];
|
||||
f2 = dfmstate.meas[6];
|
||||
}
|
||||
Serial.printf("Meas: %f %f %f\n", f, f1, f2);
|
||||
// as in autorx / dfm
|
||||
float BB0 = 3260.0; // B/Kelvin, fit -55C..+40C
|
||||
float T0 = 25 + 273.15; // t0=25C
|
||||
float R0 = 5.0e3; // R0=R25=5k
|
||||
float Rf = 220e3; // Rf = 220k
|
||||
float g = f2/Rf;
|
||||
float R = (f-f1) / g; // meas[0,3,4] > 0 ?
|
||||
float T = 0; // T/Kelvin
|
||||
if (f*f1*f2 == 0) R = 0;
|
||||
if (R > 0) T = 1/(1/T0 + 1/BB0 * log(R/R0));
|
||||
T = T - 273.15; // Celsius
|
||||
if(T<-100 || T>50) {
|
||||
Serial.printf("Temperature invalid: %f\n", T);
|
||||
return NAN;
|
||||
}
|
||||
return T;
|
||||
}
|
||||
|
||||
void DFM::decodeCFG(uint8_t *cfg)
|
||||
{
|
||||
SondeData *si = &(sonde.si()->d);
|
||||
// new ID
|
||||
finddfname(cfg);
|
||||
// get meas
|
||||
uint8_t conf_id = (*cfg)>>4;
|
||||
if(conf_id<=6) {
|
||||
uint32_t val = (cfg[1]<<12) | (cfg[2]<<4) | cfg[3];
|
||||
uint8_t exp = cfg[0] & 0xF;
|
||||
dfmstate.meas[conf_id] = val / (float)(1<<exp);
|
||||
Serial.printf("meas %d is %f (%d,%d)\n", conf_id, dfmstate.meas[conf_id], val, exp);
|
||||
}
|
||||
// get batt
|
||||
if(si->validID && si->subtype>=0x0A) {
|
||||
// otherwise don't try, as we might not have the right type yet...
|
||||
int cid = (si->subtype >= 0x0C) ? 0x7 : 0x5;
|
||||
if(conf_id == cid) {
|
||||
uint16_t val = cfg[1]<<8 | cfg[2];
|
||||
si->batteryVoltage = val / 1000.0;
|
||||
Serial.printf("battery: %f\n", si->batteryVoltage);
|
||||
}
|
||||
}
|
||||
// new aprs ID (dxlaprs, autorx) is now "D" + serial (8 digits) by consensus
|
||||
memcpy(sonde.si()->d.ser, sonde.si()->d.id+1, 9);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// not used any more
|
||||
static int bitCount(int x) {
|
||||
int m4 = 0x1 | (0x1<<8) | (0x1<<16) | (0x1<<24);
|
||||
int m1 = 0xFF;
|
||||
|
@ -338,6 +408,7 @@ static int bitCount(int x) {
|
|||
int s1 = (s4&m1) + ((s4>>8)&m1) + ((s4>>16)&m1) + ((s4>>24)&m1);
|
||||
return s1;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t MON[]={0,0,31,59,90,120,151,181,212,243,273,304,334};
|
||||
|
||||
|
@ -346,24 +417,66 @@ void DFM::decodeDAT(uint8_t *dat)
|
|||
// 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("]: ");
|
||||
// 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] < dfmstate.lastdat) dfmstate.good = 0; // next iteration detected
|
||||
}
|
||||
dfmstate.lastdat = dat[6];
|
||||
|
||||
// We handle this case already here, because we need to update dfmstate.datesec before the cycle complete handling
|
||||
if( dat[6]==8 ) {
|
||||
int y = (dat[0]<<4) + (dat[1]>>4);
|
||||
int m = dat[1]&0x0F;
|
||||
int d = dat[2]>>3;
|
||||
int h = ((dat[2]&0x07)<<2) + (dat[3]>>6);
|
||||
int mi = (dat[3]&0x3F);
|
||||
Serial.printf("Date: %04d-%02d-%02d %02d:%02dz ", y, m, d, h, mi);
|
||||
si->sats = dat[4];
|
||||
si->validPos |= 0x40;
|
||||
// convert to unix time
|
||||
int tt = (y-1970)*365 + (y-1969)/4; // days since 1970
|
||||
if(m<=12) { tt += MON[m]; if((y%4)==0 && m>2) tt++; }
|
||||
tt = (tt+d-1)*(60*60*24) + h*3600 + mi*60;
|
||||
dfmstate.datesec = tt;
|
||||
dfmstate.good |= 0x100;
|
||||
}
|
||||
else if( dat[6]>8 ) return; // we ignore those...
|
||||
|
||||
/* Here we update data that should be updated only after receiving a "complete" frame (mainly for consistent SondeHub exports)
|
||||
* We do this (a) when there is a DAT8 block and (b) when there is wrap from DAT7 to DAT0, for these fields:
|
||||
* => frame
|
||||
* => vframe (only used for SondeHub as virtual frame number)
|
||||
* => time (calculated with using date and msec)
|
||||
* [assuming that if there is no DAT8, then the date value did not change.]
|
||||
*/
|
||||
|
||||
if( dat[6]==8 || dat[6] < dfmstate.lastdat) { // After DAT8, or after a "warp around"
|
||||
if( dfmstate.good&1 ) si->frame = dfmstate.frame;
|
||||
if( (dfmstate.good&0x102)==0x102 ) {
|
||||
si->time = dfmstate.datesec + dfmstate.msec/1000;
|
||||
// Lets be consistent with autorx: the timestamp uses the msec value truncated to seconds,
|
||||
// whereas the virtual frame number for DFM uses the msec value rounded to full seconds.
|
||||
// Actually, tt is real UTC, and the transformation to GPS seconds lacks adjusting for leap seconds
|
||||
si->vframe = dfmstate.datesec + (dfmstate.msec+500)/1000 - 315964800;
|
||||
}
|
||||
// All fields updated? 1=OK, 2=with errors
|
||||
Serial.printf("Cycle done: good is %x\n", dfmstate.good);
|
||||
si->temperature = get_Temp();
|
||||
Serial.printf("Temp: %f\n", si->temperature);
|
||||
dfmstate.cycledone = ((dfmstate.good&0x11F)==0x11F) ? 1 : 2;
|
||||
dfmstate.good = 0;
|
||||
dfmstate.lastdat = 0;
|
||||
} else {
|
||||
dfmstate.lastdat = dat[6];
|
||||
}
|
||||
dfmstate.good |= (1<<dat[6]);
|
||||
switch(dat[6]) {
|
||||
case 0:
|
||||
Serial.print("Packet counter: "); Serial.print(dat[3]);
|
||||
si->frame = dat[3];
|
||||
dfmstate.frame = dat[3];
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
int val = (((uint16_t)dat[4])<<8) + (uint16_t)dat[5];
|
||||
Serial.print("UTC-msec: "); Serial.print(val);
|
||||
dfmstate.msec = val;
|
||||
uint32_t tmp = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]);
|
||||
si->sats = bitCount(tmp);
|
||||
//uint32_t tmp = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]);
|
||||
//si->sats = bitCount(tmp);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
|
@ -375,7 +488,7 @@ void DFM::decodeDAT(uint8_t *dat)
|
|||
Serial.print(", hor-V: "); Serial.print(vh*0.01);
|
||||
si->lat = lat*0.0000001;
|
||||
si->hs = vh*0.01;
|
||||
si->validPos |= 0x11;
|
||||
if(lat!=0 || vh!=0) si->validPos |= 0x11; else si->validPos &= ~0x11;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
|
@ -383,11 +496,11 @@ void DFM::decodeDAT(uint8_t *dat)
|
|||
float lon, dir;
|
||||
lon = (int32_t)(((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + (uint32_t)dat[3]);
|
||||
dir = ((uint16_t)dat[4]<<8) + dat[5];
|
||||
Serial.print("GPS-lon: "); Serial.print(lon*0.0000001);
|
||||
Serial.print(", dir: "); Serial.print(dir*0.01);
|
||||
si->lon = lon*0.0000001;
|
||||
si->dir = dir*0.01;
|
||||
si->validPos |= 0x42;
|
||||
Serial.print("GPS-lon: "); Serial.print(si->lon);
|
||||
Serial.print(", dir: "); Serial.print(si->dir);
|
||||
if(lon != 0 || dir != 0) si->validPos |= 0x22; else si->validPos &= ~0x22;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
|
@ -399,32 +512,11 @@ void DFM::decodeDAT(uint8_t *dat)
|
|||
Serial.print(", vv: "); Serial.print(vv*0.01);
|
||||
si->alt = alt*0.01;
|
||||
si->vs = vv*0.01;
|
||||
si->validPos |= 0x0C;
|
||||
if(alt!=0 || vv != 0) si->validPos |= 0x0C; else si->validPos &= ~0x0C;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
{
|
||||
int y = (dat[0]<<4) + (dat[1]>>4);
|
||||
int m = dat[1]&0x0F;
|
||||
int d = dat[2]>>3;
|
||||
int h = ((dat[2]&0x07)<<2) + (dat[3]>>6);
|
||||
int mi = (dat[3]&0x3F);
|
||||
char buf[100];
|
||||
snprintf(buf, 100, "%04d-%02d-%02d %02d:%02dz", y, m, d, h, mi);
|
||||
Serial.print("Date: "); Serial.print(buf);
|
||||
// convert to unix time
|
||||
int tt = (y-1970)*365 + (y-1969)/4; // days since 1970
|
||||
if(m<=12) { tt += MON[m]; if((y%4)==0 && m>2) tt++; }
|
||||
tt = (tt+d-1)*(60*60*24) + h*3600 + mi*60;
|
||||
si->time = tt + dfmstate.msec/1000;
|
||||
// Lets be consistent with autorx: the timestamp uses the msec value truncated to seconds,
|
||||
// whereas the virtual frame number for DFM uses the msec value rounded to full seconds.
|
||||
// Actually, tt is real UTC, and the transformation to GPS seconds lacks adjusting for leap seconds
|
||||
si->vframe = tt + (dfmstate.msec+500)/1000 - 315964800;
|
||||
// maybe TODO: if we missed the type 0 frame, we still might caculate the right seconds from system time.
|
||||
// but we only send time stamps to external servers (in particular to sondehub), if all
|
||||
// required frame types have been correctly decoded, so this does not matter much.
|
||||
}
|
||||
// handled above
|
||||
break;
|
||||
default:
|
||||
Serial.print("(?)");
|
||||
|
@ -432,6 +524,7 @@ void DFM::decodeDAT(uint8_t *dat)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void DFM::bitsToBytes(uint8_t *bits, uint8_t *bytes, int len)
|
||||
{
|
||||
int i;
|
||||
|
@ -504,6 +597,7 @@ int DFM::receive() {
|
|||
|
||||
// tentative continuous RX version...
|
||||
unsigned long t0 = millis();
|
||||
dfmstate.cycledone = 0;
|
||||
while( ( millis() - t0 ) < 1300 ) {
|
||||
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||
if ( bitRead(value, 7) ) {
|
||||
|
@ -526,22 +620,16 @@ int DFM::receive() {
|
|||
} else {
|
||||
if(haveNewFrame) {
|
||||
//Serial.printf("DFM::receive(): new frame complete after %ldms\n", millis()-t0);
|
||||
Serial.printf("receive newframe: %d, good: %x\n", rxframes, dfmstate.good);
|
||||
haveNewFrame = 0;
|
||||
rxframes--;
|
||||
if(dfmstate.good & 0x100) {
|
||||
if(dfmstate.good & 0x11E) {
|
||||
dfmstate.good = 0; return RX_OK; // type 8 frame has been received
|
||||
} else {
|
||||
dfmstate.good = 0; return RX_ERROR;
|
||||
}
|
||||
}
|
||||
if(rxframes==0) return RX_ERROR;
|
||||
// OK: All DAT frames (0/1/2/3/4/8) have been received in the last cycle
|
||||
if(dfmstate.cycledone==1) return RX_OK;
|
||||
if(dfmstate.cycledone>1 || rxframes==0) return RX_ERROR;
|
||||
}
|
||||
delay(2);
|
||||
}
|
||||
}
|
||||
return rxframes == 5 ? RX_TIMEOUT : RX_OK;
|
||||
return rxframes == 5 ? RX_TIMEOUT : RX_ERROR;
|
||||
}
|
||||
|
||||
int DFM::decodeFrameDFM(uint8_t *data) {
|
||||
|
@ -552,6 +640,7 @@ int DFM::decodeFrameDFM(uint8_t *data) {
|
|||
int ret0 = hamming(hamming_conf, 7, block_conf);
|
||||
int ret1 = hamming(hamming_dat1, 13, block_dat1);
|
||||
int ret2 = hamming(hamming_dat2, 13, block_dat2);
|
||||
//Serial.printf("Hamming returns %d %d %d -- %d\n", ret0, ret1, ret2, ret0|ret1|ret2);
|
||||
|
||||
byte byte_conf[4], byte_dat1[7], byte_dat2[7];
|
||||
bitsToBytes(block_conf, byte_conf, 7);
|
||||
|
@ -561,11 +650,14 @@ int DFM::decodeFrameDFM(uint8_t *data) {
|
|||
printRaw("CFG", 7, ret0, byte_conf);
|
||||
printRaw("DAT", 13, ret1, byte_dat1);
|
||||
printRaw("DAT", 13, ret2, byte_dat2);
|
||||
decodeCFG(byte_conf);
|
||||
decodeDAT(byte_dat1);
|
||||
decodeDAT(byte_dat2);
|
||||
if (ret0>=0) decodeCFG(byte_conf);
|
||||
if (ret1>=0 && ret1<=4) decodeDAT(byte_dat1);
|
||||
if (ret2>=0 && ret2<=4) decodeDAT(byte_dat2);
|
||||
Serial.println("");
|
||||
return RX_OK;
|
||||
// Consistent with autorx: If more than 4 corrected bit errors in DAT block, assume it is possibly corrupt and
|
||||
// don't treat it as a correct frame (ttgo display shows data anyway, but it is not sent to external sites)
|
||||
if(ret1>4 || ret2>4) return RX_ERROR;
|
||||
return (ret0|ret1|ret2)>=0 ? RX_OK : RX_ERROR;
|
||||
}
|
||||
|
||||
// moved to a single function in Sonde(). This function can be used for additional
|
||||
|
|
|
@ -1204,7 +1204,7 @@ void Display::drawString(DispEntry *de, const char *str) {
|
|||
|
||||
void Display::drawLat(DispEntry *de) {
|
||||
rdis->setFont(de->fmt);
|
||||
if(!sonde.si()->d.validPos) {
|
||||
if(!VALIDPOS(sonde.si()->d.validPos)) {
|
||||
drawString(de,"<?""?> ");
|
||||
return;
|
||||
}
|
||||
|
@ -1213,7 +1213,7 @@ void Display::drawLat(DispEntry *de) {
|
|||
}
|
||||
void Display::drawLon(DispEntry *de) {
|
||||
rdis->setFont(de->fmt);
|
||||
if(!sonde.si()->d.validPos) {
|
||||
if(!VALIDPOS(sonde.si()->d.validPos)) {
|
||||
drawString(de,"<?""?> ");
|
||||
return;
|
||||
}
|
||||
|
@ -1222,7 +1222,7 @@ void Display::drawLon(DispEntry *de) {
|
|||
}
|
||||
void Display::drawAlt(DispEntry *de) {
|
||||
rdis->setFont(de->fmt);
|
||||
if(!sonde.si()->d.validPos) {
|
||||
if(!VALIDALT(sonde.si()->d.validPos)) {
|
||||
drawString(de," ");
|
||||
return;
|
||||
}
|
||||
|
@ -1233,7 +1233,7 @@ void Display::drawAlt(DispEntry *de) {
|
|||
}
|
||||
void Display::drawHS(DispEntry *de) {
|
||||
rdis->setFont(de->fmt);
|
||||
if(!sonde.si()->d.validPos) {
|
||||
if(!VALIDHS(sonde.si()->d.validPos)) {
|
||||
drawString(de," ");
|
||||
return;
|
||||
}
|
||||
|
@ -1248,7 +1248,7 @@ void Display::drawHS(DispEntry *de) {
|
|||
}
|
||||
void Display::drawVS(DispEntry *de) {
|
||||
rdis->setFont(de->fmt);
|
||||
if(!sonde.si()->d.validPos) {
|
||||
if(!VALIDVS(sonde.si()->d.validPos)) {
|
||||
drawString(de," ");
|
||||
return;
|
||||
}
|
||||
|
@ -1459,13 +1459,13 @@ void Display::calcGPS() {
|
|||
valid = true;
|
||||
}
|
||||
// distance
|
||||
if( valid && (sonde.si()->d.validPos&0x03)==0x03 && (layout->usegps&GPSUSE_DIST)) {
|
||||
if( valid && VALIDPOS(sonde.si()->d.validPos) && (layout->usegps&GPSUSE_DIST)) {
|
||||
gpsDist = (int)calcLatLonDist(mylat, mylon, sonde.si()->d.lat, sonde.si()->d.lon);
|
||||
} else {
|
||||
gpsDist = -1;
|
||||
}
|
||||
// bearing
|
||||
if( valid && (sonde.si()->d.validPos&0x03)==0x03 && (layout->usegps&GPSUSE_BEARING)) {
|
||||
if( valid && VALIDPOS(sonde.si()->d.validPos&0x03) && (layout->usegps&GPSUSE_BEARING)) {
|
||||
float lat1 = radians(mylat);
|
||||
float lat2 = radians(sonde.si()->d.lat);
|
||||
float lon1 = radians(mylon);
|
||||
|
@ -1522,7 +1522,7 @@ void Display::drawGPS(DispEntry *de) {
|
|||
{
|
||||
// distance
|
||||
// equirectangular approximation is good enough
|
||||
if( (sonde.si()->d.validPos&0x03)!=0x03 ) {
|
||||
if( !VALIDPOS(sonde.si()->d.validPos) ) {
|
||||
snprintf(buf, 16, "no pos ");
|
||||
if(de->extra && *de->extra=='5') buf[5]=0;
|
||||
} else if( disp.gpsDist < 0 ) {
|
||||
|
|
|
@ -272,7 +272,7 @@ extern const int N_CONFIG;
|
|||
void Sonde::checkConfig() {
|
||||
if(config.maxsonde > MAXSONDE) config.maxsonde = MAXSONDE;
|
||||
if(config.sondehub.fiinterval<5) config.sondehub.fiinterval = 5;
|
||||
if(config.sondehub.fimaxdist>500) config.sondehub.fimaxdist = 500;
|
||||
if(config.sondehub.fimaxdist>700) config.sondehub.fimaxdist = 700;
|
||||
if(config.sondehub.fimaxage>48) config.sondehub.fimaxage = 48;
|
||||
if(config.sondehub.fimaxdist==0) config.sondehub.fimaxdist = 150;
|
||||
if(config.sondehub.fimaxage==0) config.sondehub.fimaxage = 2;
|
||||
|
@ -487,14 +487,13 @@ void Sonde::receive() {
|
|||
}
|
||||
|
||||
// state information for RX_TIMER / NORX_TIMER events
|
||||
if(res==0) { // RX OK
|
||||
flashLed(700);
|
||||
if(res==RX_OK || res==RX_ERROR) { // something was received...
|
||||
flashLed( (res==RX_OK)?700:100);
|
||||
if(si->lastState != 1) {
|
||||
si->rxStart = millis();
|
||||
si->lastState = 1;
|
||||
}
|
||||
} else { // RX not ok
|
||||
if(res==RX_ERROR) flashLed(100);
|
||||
} else { // RX Timeout
|
||||
//Serial.printf("Sonde::receive(): result %d (%s), laststate was %d\n", res, (res<=3)?RXstr[res]:"?", si->lastState);
|
||||
if(si->lastState != 0) {
|
||||
si->norxStart = millis();
|
||||
|
|
|
@ -74,6 +74,13 @@ extern const char *manufacturer_string[NSondeTypes];
|
|||
#define TYPE_IS_DFM(t) ( (t)==STYPE_DFM )
|
||||
#define TYPE_IS_METEO(t) ( (t)==STYPE_M10M20 || (t)==STYPE_M10 || (t)==STYPE_M20 )
|
||||
|
||||
#define VALIDPOS(x) (((x)&0x03)==0x03)
|
||||
#define VALIDALT(x) ((x)&0x04)
|
||||
#define VALIDVS(x) ((x)&0x08)
|
||||
#define VALIDHS(x) ((x)&0x10)
|
||||
#define VALIDDIR(x) ((x)&0x20)
|
||||
#define VALIDSATS(x) ((x)&0x40)
|
||||
|
||||
typedef struct st_sondedata {
|
||||
// decoded ID
|
||||
char id[10];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const char *version_name = "rdzTTGOsonde";
|
||||
const char *version_id = "devel20210928";
|
||||
const char *version_id = "devel20210930";
|
||||
const int SPIFFS_MAJOR=2;
|
||||
const int SPIFFS_MINOR=16;
|
||||
|
|
Ładowanie…
Reference in New Issue