some minor updates
This commit is contained in:
parent
e7360f2c1e
commit
da9d4367be
46
README.md
46
README.md
|
|
@ -1 +1,45 @@
|
||||||
# rdz_ttgo_sonde
|
RDZ_TTGO_SONDE
|
||||||
|
==============
|
||||||
|
|
||||||
|
This a simple, experimental, not (well) tested, and incomplete decoder for
|
||||||
|
radiosonde RS41 and DFM06/09 on a TTGO LoRa ESP32 with OLED display board.
|
||||||
|
|
||||||
|
## Button commands
|
||||||
|
You can use the button on the board (not the reset button, the second one) to
|
||||||
|
issue some commands. The software distinguishes between several inputs:
|
||||||
|
|
||||||
|
SHORT Short button press (<1.5 seconds)
|
||||||
|
DOUBLE Short button press, followed by another button press within 0.5 seconds
|
||||||
|
MID Medium-length button press (2-4 seconds)
|
||||||
|
LONG Long button press (>5 seconds)
|
||||||
|
|
||||||
|
## Wireless configuration
|
||||||
|
|
||||||
|
On startup, as well as after a LONG button press, the WiFI configuration will
|
||||||
|
be started. The board will scan available WiFi networks, if the scan results
|
||||||
|
contains a WiFi network configured with ID and Password in networks.txt, it
|
||||||
|
will connect to that network in station mode. If no known network is found, or
|
||||||
|
the connection does not suceed after 5 seconds, it instead starts in access point
|
||||||
|
mode. In both cases, the ESP32's IP address will be shown in tiny letters in the
|
||||||
|
bottom line. Then the board will switch to scanning mode.
|
||||||
|
|
||||||
|
## Scanning mode
|
||||||
|
|
||||||
|
In the scanning mode, the board will iterate over all channels configured in
|
||||||
|
channels.txt, trying to decode a radio sonde on each channel for about 1 second
|
||||||
|
for RS41, a bit less for DMF06/09. If a valid signal is found, the board switches
|
||||||
|
to receiving mode on that channel. a SHORT buttong press will also switch to
|
||||||
|
receiving mode.
|
||||||
|
|
||||||
|
## Receiving mode
|
||||||
|
|
||||||
|
In receiving mode, a single frequency will be decoded, and sonde info (ID, GPS
|
||||||
|
coordinates, RSSI) will be displayed. The bar above the IP address indicates,
|
||||||
|
for the last 18 frames, if reception was successfull (|) or failed (.)
|
||||||
|
A DOUBLE press will switch to scanning mode.
|
||||||
|
A SHORT press will switch to the next channel in channels.txt
|
||||||
|
|
||||||
|
# Spectrum mode
|
||||||
|
|
||||||
|
A medium press will active scan the whole band (400..406 MHz) and display a
|
||||||
|
spectrum diagram (each line == 50 kHz)
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,37 @@ void setupWifiList() {
|
||||||
for(int j=0; j<i; j++) { Serial.print(networks[j].id); Serial.print(": "); Serial.println(networks[j].pw); }
|
for(int j=0; j<i; j++) { Serial.print(networks[j].id); Serial.print(": "); Serial.println(networks[j].pw); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setupChannelList() {
|
||||||
|
File file = SPIFFS.open("/qrg.txt", "r");
|
||||||
|
if(!file) {
|
||||||
|
Serial.println("There was an error opening the file '/qrg.txt' for reading");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int i=0;
|
||||||
|
sonde.clearSonde();
|
||||||
|
while(file.available()) {
|
||||||
|
String line = file.readStringUntil('\n');
|
||||||
|
if(!file.available()) break;
|
||||||
|
if(line[0] == '#') continue;
|
||||||
|
char *space = strchr(line.c_str(), ' ');
|
||||||
|
if(!space) continue;
|
||||||
|
*space = 0;
|
||||||
|
float freq = atof(line.c_str());
|
||||||
|
SondeType type;
|
||||||
|
if(space[1]=='4') { type=STYPE_RS41; }
|
||||||
|
else if (space[1]=='9') { type=STYPE_DFM09; }
|
||||||
|
else if (space[1]=='6') { type=STYPE_DFM06; }
|
||||||
|
else continue;
|
||||||
|
Serial.printf("Adding %f with type %d\b",freq,type);
|
||||||
|
sonde.addSonde(freq, type);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
nNetworks = i;
|
||||||
|
Serial.print(i); Serial.println(" networks in networks.txt\n");
|
||||||
|
for(int j=0; j<i; j++) { Serial.print(networks[j].id); Serial.print(": "); Serial.println(networks[j].pw); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const char *fetchWifiPw(const char *id) {
|
const char *fetchWifiPw(const char *id) {
|
||||||
for(int i=0; i<nNetworks; i++) {
|
for(int i=0; i<nNetworks; i++) {
|
||||||
Serial.print("Comparing '");
|
Serial.print("Comparing '");
|
||||||
|
|
@ -206,10 +237,13 @@ void setup()
|
||||||
// Handle button press
|
// Handle button press
|
||||||
attachInterrupt(0, buttonISR, CHANGE);
|
attachInterrupt(0, buttonISR, CHANGE);
|
||||||
|
|
||||||
|
setupChannelList();
|
||||||
|
#if 0
|
||||||
sonde.clearSonde();
|
sonde.clearSonde();
|
||||||
sonde.addSonde(402.300, STYPE_RS41);
|
sonde.addSonde(402.300, STYPE_RS41);
|
||||||
sonde.addSonde(402.700, STYPE_RS41);
|
sonde.addSonde(402.700, STYPE_RS41);
|
||||||
sonde.addSonde(403.450, STYPE_DFM09);
|
sonde.addSonde(403.450, STYPE_DFM09);
|
||||||
|
#endif
|
||||||
/// not here, done by sonde.setup(): rs41.setup();
|
/// not here, done by sonde.setup(): rs41.setup();
|
||||||
sonde.setup();
|
sonde.setup();
|
||||||
}
|
}
|
||||||
|
|
@ -267,7 +301,7 @@ void loopScanner() {
|
||||||
enterMode(ST_DECODER);
|
enterMode(ST_DECODER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(++tries>=SCAN_MAXTRIES) {
|
if(++tries>=SCAN_MAXTRIES && !hasKeyPress()) {
|
||||||
sonde.nextConfig();
|
sonde.nextConfig();
|
||||||
tries = 0;
|
tries = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +368,7 @@ void loopWifiScan() {
|
||||||
pw=fetchWifiPw(id);
|
pw=fetchWifiPw(id);
|
||||||
if(pw) break;
|
if(pw) break;
|
||||||
}
|
}
|
||||||
if(!pw) { id="test"; pw="test"; }
|
if(1||!pw) { id="test"; pw="test"; }
|
||||||
Serial.print("Connecting to: "); Serial.println(id);
|
Serial.print("Connecting to: "); Serial.println(id);
|
||||||
u8x8.drawString(0,6, "Conn:");
|
u8x8.drawString(0,6, "Conn:");
|
||||||
u8x8.drawString(6,6, id);
|
u8x8.drawString(6,6, id);
|
||||||
|
|
@ -344,6 +378,24 @@ void loopWifiScan() {
|
||||||
Serial.print(".");
|
Serial.print(".");
|
||||||
u8x8.drawString(15,7,_scan[cnt&1]);
|
u8x8.drawString(15,7,_scan[cnt&1]);
|
||||||
cnt++;
|
cnt++;
|
||||||
|
if(cnt==4) {
|
||||||
|
WiFi.disconnect(); // retry, for my buggy FritzBox
|
||||||
|
WiFi.begin(id, pw);
|
||||||
|
}
|
||||||
|
if(cnt==10) {
|
||||||
|
WiFi.disconnect();
|
||||||
|
delay(1000);
|
||||||
|
WiFi.softAP("sonde","sondesonde");
|
||||||
|
IPAddress myIP = WiFi.softAPIP();
|
||||||
|
Serial.print("AP IP address: ");
|
||||||
|
Serial.println(myIP);
|
||||||
|
sonde.setIP(myIP.toString().c_str());
|
||||||
|
sonde.updateDisplayIP();
|
||||||
|
SetupAsyncServer();
|
||||||
|
delay(5000);
|
||||||
|
enterMode(ST_DECODER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println("");
|
Serial.println("");
|
||||||
|
|
@ -354,7 +406,7 @@ void loopWifiScan() {
|
||||||
sonde.updateDisplayIP();
|
sonde.updateDisplayIP();
|
||||||
SetupAsyncServer();
|
SetupAsyncServer();
|
||||||
delay(5000);
|
delay(5000);
|
||||||
mainState=ST_SPECTRUM;
|
enterMode(ST_DECODER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Frequency in Mhz (format nnn.nnn)
|
||||||
|
# Type (4=RS41, 6=DFM normal, DFM-06, 9=DFM inverted, DFM-09)
|
||||||
|
#
|
||||||
|
402.700 4
|
||||||
|
402.300 4
|
||||||
|
403.450 9
|
||||||
|
405.100 4
|
||||||
|
# end
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
/* DFM decoder functions */
|
/* DFM decoder functions */
|
||||||
#include "DFM.h"
|
#include "DFM.h"
|
||||||
#include "SX1278FSK.h"
|
#include "SX1278FSK.h"
|
||||||
|
#include "Sonde.h"
|
||||||
|
|
||||||
#define DFM_DEBUG 1
|
#define DFM_DEBUG 1
|
||||||
|
|
||||||
|
|
@ -167,6 +168,8 @@ int DFM::decodeCFG(uint8_t *cfg)
|
||||||
if((cfg[0]>>4)==0x06 && type==0) { // DFM-6 ID
|
if((cfg[0]>>4)==0x06 && type==0) { // DFM-6 ID
|
||||||
lowid = ((cfg[0]&0x0F)<<20) | (cfg[1]<<12) | (cfg[2]<<4) | (cfg[3]&0x0f);
|
lowid = ((cfg[0]&0x0F)<<20) | (cfg[1]<<12) | (cfg[2]<<4) | (cfg[3]&0x0f);
|
||||||
Serial.print("DFM-06 ID: "); Serial.print(lowid, HEX);
|
Serial.print("DFM-06 ID: "); Serial.print(lowid, HEX);
|
||||||
|
snprintf(sonde.si()->id, 10, "%x", lowid);
|
||||||
|
sonde.si()->validID = true;
|
||||||
}
|
}
|
||||||
if((cfg[0]>>4)==0x0A) { // DMF-9 ID
|
if((cfg[0]>>4)==0x0A) { // DMF-9 ID
|
||||||
type=9;
|
type=9;
|
||||||
|
|
@ -180,6 +183,8 @@ int 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);
|
||||||
|
sonde.si()->validID = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -204,6 +209,9 @@ int DFM::decodeDAT(uint8_t *dat)
|
||||||
vh = (dat[4]<<8) + dat[5];
|
vh = (dat[4]<<8) + dat[5];
|
||||||
Serial.print("GPS-lat: "); Serial.print(lat*0.0000001);
|
Serial.print("GPS-lat: "); Serial.print(lat*0.0000001);
|
||||||
Serial.print(", hor-V: "); Serial.print(vh*0.01);
|
Serial.print(", hor-V: "); Serial.print(vh*0.01);
|
||||||
|
sonde.si()->lat = lat*0.0000001;
|
||||||
|
sonde.si()->hs = vh*0.01;
|
||||||
|
sonde.si()->validPos |= 0x11;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
|
@ -213,6 +221,9 @@ int DFM::decodeDAT(uint8_t *dat)
|
||||||
dir = ((uint16_t)dat[4]<<8) + dat[5];
|
dir = ((uint16_t)dat[4]<<8) + dat[5];
|
||||||
Serial.print("GPS-lon: "); Serial.print(lon*0.0000001);
|
Serial.print("GPS-lon: "); Serial.print(lon*0.0000001);
|
||||||
Serial.print(", dir: "); Serial.print(dir*0.01);
|
Serial.print(", dir: "); Serial.print(dir*0.01);
|
||||||
|
sonde.si()->lon = lon*0.0000001;
|
||||||
|
sonde.si()->dir = dir*0.01;
|
||||||
|
sonde.si()->validPos |= 0x42;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
|
@ -222,6 +233,9 @@ int DFM::decodeDAT(uint8_t *dat)
|
||||||
vv = (int16_t)( (dat[4]<<8) | dat[5] );
|
vv = (int16_t)( (dat[4]<<8) | dat[5] );
|
||||||
Serial.print("GPS-height: "); Serial.print(hei*0.01);
|
Serial.print("GPS-height: "); Serial.print(hei*0.01);
|
||||||
Serial.print(", vv: "); Serial.print(vv*0.01);
|
Serial.print(", vv: "); Serial.print(vv*0.01);
|
||||||
|
sonde.si()->hei = hei*0.01;
|
||||||
|
sonde.si()->vs = vv*0.01;
|
||||||
|
sonde.si()->validPos |= 0x0C;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
|
|
@ -258,7 +272,7 @@ int DFM::receiveFrame() {
|
||||||
|
|
||||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||||
int e = sx1278.receivePacketTimeout(1000, data);
|
int e = sx1278.receivePacketTimeout(1000, data);
|
||||||
if(e) { return 1; } //if timeout... return 1
|
if(e) { return RX_TIMEOUT; } //if timeout... return 1
|
||||||
|
|
||||||
deinterleave(data, 7, hamming_conf);
|
deinterleave(data, 7, hamming_conf);
|
||||||
deinterleave(data+7, 13, hamming_dat1);
|
deinterleave(data+7, 13, hamming_dat1);
|
||||||
|
|
@ -279,6 +293,7 @@ int DFM::receiveFrame() {
|
||||||
decodeCFG(byte_conf);
|
decodeCFG(byte_conf);
|
||||||
decodeDAT(byte_dat1);
|
decodeDAT(byte_dat1);
|
||||||
decodeDAT(byte_dat2);
|
decodeDAT(byte_dat2);
|
||||||
|
return RX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
DFM dfm = DFM();
|
DFM dfm = DFM();
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,10 @@ static const uint8_t font[10][5]={
|
||||||
0x36, 0x49, 0x49, 0x49, 0x36, // 8
|
0x36, 0x49, 0x49, 0x49, 0x36, // 8
|
||||||
0x06, 0x49, 0x39, 0x29, 0x1E }; // 9; .=0x40
|
0x06, 0x49, 0x39, 0x29, 0x1E }; // 9; .=0x40
|
||||||
|
|
||||||
|
static uint8_t halfdb_tile[8]={0x80, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x00};
|
||||||
|
static uint8_t empty_tile[8]={0x80, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00};
|
||||||
|
|
||||||
|
|
||||||
void Sonde::setIP(const char *ip) {
|
void Sonde::setIP(const char *ip) {
|
||||||
int tp = 0;
|
int tp = 0;
|
||||||
int len = strlen(ip);
|
int len = strlen(ip);
|
||||||
|
|
@ -152,8 +156,11 @@ void Sonde::updateDisplayID() {
|
||||||
void Sonde::updateDisplayRSSI() {
|
void Sonde::updateDisplayRSSI() {
|
||||||
char buf[16];
|
char buf[16];
|
||||||
u8x8.setFont(u8x8_font_7x14_1x2_r);
|
u8x8.setFont(u8x8_font_7x14_1x2_r);
|
||||||
snprintf(buf, 16, "%ddB ", sonde.si()->rssi);
|
snprintf(buf, 16, "-%d ", sonde.si()->rssi/2);
|
||||||
|
int len=strlen(buf)-3;
|
||||||
|
buf[5]=0;
|
||||||
u8x8.drawString(0,6,buf);
|
u8x8.drawString(0,6,buf);
|
||||||
|
u8x8.drawTile(len,6,1,(sonde.si()->rssi&1)?halfdb_tile:empty_tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sonde::updateStat() {
|
void Sonde::updateStat() {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ typedef struct st_sondeinfo {
|
||||||
float hei;
|
float hei;
|
||||||
float vs;
|
float vs;
|
||||||
float hs;
|
float hs;
|
||||||
bool validPos;
|
float dir; // 0..360
|
||||||
|
uint8_t validPos; // bit pattern for validity of above 6 fields
|
||||||
// RSSI from receiver
|
// RSSI from receiver
|
||||||
int rssi;
|
int rssi;
|
||||||
uint8_t rxStat[20];
|
uint8_t rxStat[20];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue