Some working things...

Squashed commit of the following:

commit da9d4367be
Author: Hans P. Reiser <hr@sec.uni-passau.de>
Date:   Fri Apr 5 23:32:26 2019 +0200

    some minor updates

commit e7360f2c1e
Author: Hans P. Reiser <hr@sec.uni-passau.de>
Date:   Fri Apr 5 20:05:22 2019 +0200

    incremental enhancements on train trip

commit b3ac2c5506
Author: Hans P. Reiser <hr@sec.uni-passau.de>
Date:   Fri Apr 5 20:05:18 2019 +0200

    incremental enhancements on train trip

commit ab4367992e
Author: Hans P. Reiser <hr@sec.uni-passau.de>
Date:   Thu Apr 4 23:46:48 2019 +0200

    some more testing

commit d02d687670
Author: Hans P. Reiser <hr@sec.uni-passau.de>
Date:   Thu Apr 4 23:46:37 2019 +0200

    some more testing

commit 34f9971143
Author: Hansi Reiser <dl9rdz@darc.de>
Date:   Thu Apr 4 08:11:14 2019 +0200

    scanner-test

commit a22bb43c89
Author: Hansi Reiser <dl9rdz@darc.de>
Date:   Thu Apr 4 08:10:56 2019 +0200

    scanner-test
pull/4/head
Hans P. Reiser 2019-04-06 22:22:08 +02:00
rodzic c4f3e8d63b
commit f9a16f827c
13 zmienionych plików z 817 dodań i 144 usunięć

Wyświetl plik

@ -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)

Wyświetl plik

@ -1,14 +1,15 @@
#include <U8x8lib.h>
#include <Sonde.h>
#include <WiFi.h> #include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <RS41.h> #include <SPIFFS.h>
#include <SX1278FSK.h> #include <U8x8lib.h>
#include <rsc.h>
#include <SPI.h> #include <SPI.h>
#include <SX1278FSK.h>
#include <Sonde.h>
#include <Scanner.h>
//#include <RS41.h>
//#include <DFM.h>
#define LORA_LED 9 #define LORA_LED 9
// I2C OLED Display works with SSD1306 driver // I2C OLED Display works with SSD1306 driver
@ -22,90 +23,169 @@ U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ OLED_SCL, /* data=*/ OLED_SDA
//U8G2_SSD1306_128X64_NONAME_F_SW_I2C Display(U8G2_R0, /* clock=*/ OLED_SCL, /* data=*/ OLED_SDA, /* reset=*/ OLED_RST); // Full framebuffer, SW I2C //U8G2_SSD1306_128X64_NONAME_F_SW_I2C Display(U8G2_R0, /* clock=*/ OLED_SCL, /* data=*/ OLED_SDA, /* reset=*/ OLED_RST); // Full framebuffer, SW I2C
int e; int e;
char my_packet[100];
const char* ssid = "DinoGast"; AsyncWebServer server(80);
const char* password = "Schokolade";
WiFiServer server(80); // Set LED GPIO
const int ledPin = 2;
pthread_t wifithread; // Stores LED state
String ledState;
int conn = 0; // Replaces placeholder with LED state value
String currentLine; String processor(const String& var){
WiFiClient client; Serial.println(var);
unsigned long lastdu; if(var == "STATE"){
if(digitalRead(ledPin)){
ledState = "ON";
}
else{
ledState = "OFF";
}
Serial.print(ledState);
return ledState;
}
return String();
}
void wifiloop(void *arg){ void SetupAsyncServer() {
lastdu=millis(); // Route for root / web page
while(true) { server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
if(millis()-lastdu>500) { request->send(200, "text/plain", "Hello, world");
// This is too slow to do in main loop });
//u8x8.setFont(u8x8_font_chroma48medium8_r);
//u8x8.clearDisplay(); server.on("/index.html", HTTP_GET, [](AsyncWebServerRequest *request){
sonde.updateDisplay(); request->send(SPIFFS, "/index.html", String(), false, processor);
lastdu=millis(); });
// Route to load style.css file
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
// Route to set GPIO to HIGH
server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(ledPin, HIGH);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Route to set GPIO to LOW
server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(ledPin, LOW);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Start server
server.begin();
}
int nNetworks;
struct { String id; String pw; } networks[20];
void setupWifiList() {
File file = SPIFFS.open("/networks.txt", "r");
if(!file){
Serial.println("There was an error opening the file '/networks.txt' for reading");
return;
}
int i=0;
while(file.available()) {
String line = file.readStringUntil('\n');
if(!file.available()) break;
networks[i].id = line;
networks[i].pw = file.readStringUntil('\n');
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); }
}
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) {
for(int i=0; i<nNetworks; i++) {
Serial.print("Comparing '");
Serial.print(id);
Serial.print("' and '");
Serial.print(networks[i].id.c_str());
Serial.println("'");
if(strcmp(id,networks[i].id.c_str())==0) return networks[i].pw.c_str();
}
return NULL;
} }
delay(1); enum KeyPress { KP_NONE=0, KP_SHORT, KP_DOUBLE, KP_MID, KP_LONG };
if(!conn) {
client = server.available(); // listen for incoming clients struct Button {
if (client) { // if you get a client, const uint8_t PIN;
Serial.println("New Client."); // print a message out the serial port uint32_t numberKeyPresses;
currentLine = ""; // make a String to hold incoming data from the client KeyPress pressed;
conn = 1; unsigned long press_ts;
} boolean doublepress;
};
Button button1 = {0, 0, KP_NONE, 0, false};
void IRAM_ATTR buttonISR() {
if(digitalRead(0)==0) { // Button down
if(millis()-button1.press_ts<500) {
// Double press
button1.doublepress = true;
} else { } else {
if(!client.connected()) { // loop while the client's connected button1.doublepress = false;
conn = 0;
Serial.println("Client no longer connected");
continue;
} }
while (client.available()) { // if there's bytes to read from the client, button1.press_ts = millis();
char c = client.read(); // read a byte, then } else { //Button up
Serial.write(c); // print it out the serial monitor unsigned int elapsed = millis()-button1.press_ts;
if (c == '\n') { // if the byte is a newline character if(elapsed>1500) {
if(elapsed<4000) { button1.pressed=KP_MID; }
// if the current line is blank, you got two newline characters in a row. else { button1.pressed=KP_LONG; }
// that's the end of the client HTTP request, so send a response: } else {
if (currentLine.length() == 0) { if(button1.doublepress) button1.pressed=KP_DOUBLE;
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) else button1.pressed=KP_SHORT;
// and a content-type so the client knows what's coming, then a blank line: }
client.println("HTTP/1.1 200 OK"); button1.numberKeyPresses += 1;
client.println("Content-type:text/html"); button1.press_ts = millis();
client.println();
// the content of the HTTP response follows the header:
client.print("Click <a href=\"/H\">here</a> to turn the LED on pin 5 on.<br>");
client.print("Click <a href=\"/L\">here</a> to turn the LED on pin 5 off.<br>");
// The HTTP response ends with another blank line:
client.println();
// break out of the while loop:
// close the connection:
client.stop();
Serial.println("Client Disconnected.");
continue;
} else { // if you got a newline, then clear currentLine:
currentLine = "";
} }
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
} }
// Check to see if the client request was "GET /H" or "GET /L": int getKeyPress() {
if (currentLine.endsWith("GET /H")) { KeyPress p = button1.pressed;
digitalWrite(5, HIGH); // GET /H turns the LED on button1.pressed = KP_NONE;
} return p;
if (currentLine.endsWith("GET /L")) {
digitalWrite(5, LOW); // GET /L turns the LED off
}
}
}
} }
int hasKeyPress() {
return button1.pressed;
} }
void setup() void setup()
@ -115,26 +195,17 @@ void setup()
u8x8.begin(); u8x8.begin();
pinMode(LORA_LED, OUTPUT); pinMode(LORA_LED, OUTPUT);
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) { // Initialize SPIFFS
delay(500); if(!SPIFFS.begin(true)){
Serial.print("."); Serial.println("An Error has occurred while mounting SPIFFS");
return;
} }
Serial.println(""); setupWifiList();
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
xTaskCreatePinnedToCore(wifiloop, "WifiServer", 10240, NULL, 10, NULL, 0);
rs41.setup();
#if 0
if(rs41.setFrequency(402700000)==0) { if(rs41.setFrequency(402700000)==0) {
Serial.println(F("Setting freq: SUCCESS ")); Serial.println(F("Setting freq: SUCCESS "));
} else { } else {
@ -143,8 +214,9 @@ void setup()
float f = sx1278.getFrequency(); float f = sx1278.getFrequency();
Serial.print("Frequency set to "); Serial.print("Frequency set to ");
Serial.println(f); Serial.println(f);
#endif
sx1278.setLNAGain(-48); sx1278.setLNAGain(0); //-48);
int gain = sx1278.getLNAGain(); int gain = sx1278.getLNAGain();
Serial.print("RX LNA Gain is "); Serial.print("RX LNA Gain is ");
Serial.println(gain); Serial.println(gain);
@ -162,16 +234,195 @@ void setup()
// } // }
// xTaskCreate(mainloop, "MainServer", 10240, NULL, 10, NULL); // xTaskCreate(mainloop, "MainServer", 10240, NULL, 10, NULL);
// Handle button press
attachInterrupt(0, buttonISR, CHANGE);
setupChannelList();
#if 0
sonde.clearSonde();
sonde.addSonde(402.300, STYPE_RS41);
sonde.addSonde(402.700, STYPE_RS41);
sonde.addSonde(403.450, STYPE_DFM09);
#endif
/// not here, done by sonde.setup(): rs41.setup();
sonde.setup();
} }
enum MainState { ST_DECODER, ST_SCANNER, ST_SPECTRUM, ST_WIFISCAN };
static MainState mainState = ST_DECODER;
void enterMode(int mode) {
mainState = (MainState)mode;
sonde.clearDisplay();
}
void loopDecoder() {
switch(getKeyPress()) {
case KP_SHORT:
sonde.nextConfig();
break;
case KP_DOUBLE:
enterMode(ST_SCANNER);
return;
case KP_MID:
enterMode(ST_SPECTRUM);
return;
case KP_LONG:
enterMode(ST_WIFISCAN);
return;
}
// sonde knows the current type and frequency, and delegates to the right decoder
sonde.receiveFrame();
sonde.updateDisplay();
}
#define SCAN_MAXTRIES 1
void loopScanner() {
sonde.updateDisplayScanner();
static int tries=0;
switch(getKeyPress()) {
case KP_SHORT:
enterMode(ST_DECODER);
return;
case KP_DOUBLE: break; /* ignored */
case KP_MID:
enterMode(ST_SPECTRUM);
return;
case KP_LONG:
enterMode(ST_WIFISCAN);
return;
}
// receiveFrame returns 0 on success, 1 on timeout
int res = sonde.receiveFrame(); // Maybe instead of receiveFrame, just detect if right type is present? TODO
Serial.print("Scanner: receiveFrame returned");
Serial.println(res);
if(res==0) {
enterMode(ST_DECODER);
return;
}
if(++tries>=SCAN_MAXTRIES && !hasKeyPress()) {
sonde.nextConfig();
tries = 0;
}
}
void loopSpectrum() {
switch(getKeyPress()) {
case KP_SHORT: /* move selection of peak, TODO */
sonde.nextConfig(); // TODO: Should be set specific frequency
enterMode(ST_DECODER);
return;
case KP_MID: /* restart, TODO */ break;
case KP_LONG:
enterMode(ST_WIFISCAN);
return;
case KP_DOUBLE: /* ignore */ break;
default: break;
}
scanner.scan();
scanner.plotResult();
}
String translateEncryptionType(wifi_auth_mode_t encryptionType) {
switch (encryptionType) {
case (WIFI_AUTH_OPEN):
return "Open";
case (WIFI_AUTH_WEP):
return "WEP";
case (WIFI_AUTH_WPA_PSK):
return "WPA_PSK";
case (WIFI_AUTH_WPA2_PSK):
return "WPA2_PSK";
case (WIFI_AUTH_WPA_WPA2_PSK):
return "WPA_WPA2_PSK";
case (WIFI_AUTH_WPA2_ENTERPRISE):
return "WPA2_ENTERPRISE";
}
}
static char* _scan[2]={"/","\\"};
void loopWifiScan() {
u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.drawString(0,0,"WiFi Scan...");
int line=0;
int cnt=0;
WiFi.mode(WIFI_STA);
const char *id, *pw;
int n = WiFi.scanNetworks();
for (int i = 0; i < n; i++) {
Serial.print("Network name: ");
Serial.println(WiFi.SSID(i));
u8x8.drawString(0,1+line,WiFi.SSID(i).c_str());
line = (line+1)%5;
Serial.print("Signal strength: ");
Serial.println(WiFi.RSSI(i));
Serial.print("MAC address: ");
Serial.println(WiFi.BSSIDstr(i));
Serial.print("Encryption type: ");
String encryptionTypeDescription = translateEncryptionType(WiFi.encryptionType(i));
Serial.println(encryptionTypeDescription);
Serial.println("-----------------------");
id=WiFi.SSID(i).c_str();
pw=fetchWifiPw(id);
if(pw) break;
}
if(1||!pw) { id="test"; pw="test"; }
Serial.print("Connecting to: "); Serial.println(id);
u8x8.drawString(0,6, "Conn:");
u8x8.drawString(6,6, id);
WiFi.begin(id, pw);
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
u8x8.drawString(15,7,_scan[cnt&1]);
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("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
sonde.setIP(WiFi.localIP().toString().c_str());
sonde.updateDisplayIP();
SetupAsyncServer();
delay(5000);
enterMode(ST_DECODER);
}
void loop() { void loop() {
Serial.println("Running main loop"); Serial.println("Running main loop");
switch(mainState) {
case ST_DECODER: loopDecoder(); break;
case ST_SCANNER: loopScanner(); break;
case ST_SPECTRUM: loopSpectrum(); break;
case ST_WIFISCAN: loopWifiScan(); break;
}
#if 0
//wifiloop(NULL); //wifiloop(NULL);
//e = dfm.receiveFrame(); //e = dfm.receiveFrame();
e = rs41.receiveFrame(); //e = rs41.receiveFrame();
#if 0 delay(1000);
int rssi = sx1278.getRSSI(); int rssi = sx1278.getRSSI();
Serial.print(" RSSI: "); Serial.print(" RSSI: ");
Serial.print(rssi); Serial.print(rssi);

Wyświetl plik

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<title>ESP32 Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>ESP32 Web Server</h1>
<!--
<p>GPIO state: <strong> %STATE%</strong></p>
<p><a href="/on"><button class="button">ON</button></a></p>
<p><a href="/off"><button class="button button2">OFF</button></a></p>
-->
<table class="KKK">
<tr>
<th></th>
<th style="width:100px">ID</th>
<th style="width:100px">PW</th>
</tr>
<tr>
<td>1</td>
<td contenteditable>DinoGast</td>
<td contenteditable>Schokolade</td>
<tr>
<td>2</td>
<td contenteditable></td>
<td contenteditable></td>
</tr>
</body>
</html>

Wyświetl plik

@ -0,0 +1,4 @@
DinoGast
Schokolade
AndroidDD
dl9rdzhr

Wyświetl plik

@ -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

Wyświetl plik

@ -0,0 +1,28 @@
html {
font-family: Helvetica;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h1{
color: #0F3376;
padding: 2vh;
}
p{
font-size: 1.5rem;
}
.button {
display: inline-block;
background-color: #008CBA;
border: none;
border-radius: 4px;
color: white;
padding: 16px 40px;
text-decoration: none;
font-size: 30px;
margin: 2px;
cursor: pointer;
}
.button2 {
background-color: #f44336;
}

Wyświetl plik

@ -11,6 +11,7 @@
#include "SX1278FSK.h" #include "SX1278FSK.h"
#include "SPI.h" #include "SPI.h"
#include <Sonde.h>
SX1278FSK::SX1278FSK() SX1278FSK::SX1278FSK()
{ {
@ -98,7 +99,7 @@ byte SX1278FSK::readRegister(byte address)
digitalWrite(SX1278_SS,LOW); digitalWrite(SX1278_SS,LOW);
delay(1); //delay(1);
bitClear(address, 7); // Bit 7 cleared to write in registers bitClear(address, 7); // Bit 7 cleared to write in registers
SPI.transfer(address); SPI.transfer(address);
value = SPI.transfer(0x00); value = SPI.transfer(0x00);
@ -129,7 +130,7 @@ void SX1278FSK::writeRegister(byte address, byte data)
{ {
digitalWrite(SX1278_SS,LOW); digitalWrite(SX1278_SS,LOW);
delay(1); //delay(1);
bitSet(address, 7); // Bit 7 set to read from registers bitSet(address, 7); // Bit 7 set to read from registers
SPI.transfer(address); SPI.transfer(address);
SPI.transfer(data); SPI.transfer(data);
@ -648,6 +649,9 @@ uint8_t SX1278FSK::receive()
return state; return state;
} }
// ugly. shouldn't be here in a nice software design
extern int hasKeyPress();
/* /*
Function: Configures the module to receive a packet Function: Configures the module to receive a packet
Returns: Integer that determines if there has been any error Returns: Integer that determines if there has been any error
@ -682,7 +686,7 @@ uint8_t SX1278FSK::receivePacketTimeout(uint32_t wait, byte *data)
value = readRegister(REG_IRQ_FLAGS2); value = readRegister(REG_IRQ_FLAGS2);
byte ready=0; byte ready=0;
// while not yet done or FIFO not yet empty // while not yet done or FIFO not yet empty
while( (!ready || bitRead(value,6)==0) && (millis() - previous < wait) ) while( (!ready || bitRead(value,6)==0) && (millis() - previous < wait) &&(!hasKeyPress()) )
{ {
if( bitRead(value,2)==1 ) ready=1; if( bitRead(value,2)==1 ) ready=1;
if( bitRead(value, 6) == 0 ) { // FIFO not empty if( bitRead(value, 6) == 0 ) { // FIFO not empty
@ -690,6 +694,7 @@ uint8_t SX1278FSK::receivePacketTimeout(uint32_t wait, byte *data)
if(di==1) { if(di==1) {
int rssi=getRSSI(); int rssi=getRSSI();
Serial.print("Test: RSSI="); Serial.println(rssi); Serial.print("Test: RSSI="); Serial.println(rssi);
sonde.si()->rssi = rssi;
} }
if(di>520) { if(di>520) {
// TODO // TODO
@ -705,6 +710,7 @@ uint8_t SX1278FSK::receivePacketTimeout(uint32_t wait, byte *data)
Serial.println(F("** The timeout has expired **")); Serial.println(F("** The timeout has expired **"));
Serial.println(); Serial.println();
#endif #endif
sonde.si()->rssi = getRSSI();
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Setting standby FSK mode writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Setting standby FSK mode
return 1; // TIMEOUT return 1; // TIMEOUT
} }

Wyświetl plik

@ -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
@ -71,6 +72,8 @@ int DFM::setup(int inverse)
} }
int DFM::setFrequency(float frequency) { int DFM::setFrequency(float frequency) {
Serial.print("DFM: setting RX frequency to ");
Serial.println(frequency);
return sx1278.setFrequency(frequency); return sx1278.setFrequency(frequency);
} }
@ -165,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;
@ -178,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;
} }
} }
} }
@ -202,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:
@ -211,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:
@ -220,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:
@ -256,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);
@ -277,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();

Wyświetl plik

@ -133,6 +133,8 @@ int RS41::setup()
} }
int RS41::setFrequency(float frequency) { int RS41::setFrequency(float frequency) {
Serial.print("RS41: setting RX frequency to ");
Serial.println(frequency);
return sx1278.setFrequency(frequency); return sx1278.setFrequency(frequency);
} }
@ -311,11 +313,11 @@ static void posrs41(const byte b[], uint32_t b_len, uint32_t p)
z = (double)getint32(b, b_len, p+8UL)*0.01; z = (double)getint32(b, b_len, p+8UL)*0.01;
wgs84r(x, y, z, &lat, &long0, &heig); wgs84r(x, y, z, &lat, &long0, &heig);
Serial.print(" "); Serial.print(" ");
si.lat = (float)(X2C_DIVL(lat,1.7453292519943E-2)); sonde.si()->lat = (float)(X2C_DIVL(lat,1.7453292519943E-2));
Serial.print(si.lat); Serial.print(sonde.si()->lat);
Serial.print(" "); Serial.print(" ");
si.lon = (float)(X2C_DIVL(long0,1.7453292519943E-2)); sonde.si()->lon = (float)(X2C_DIVL(long0,1.7453292519943E-2));
Serial.print(si.lon); Serial.print(sonde.si()->lon);
if (heig<1.E+5 && heig>(-1.E+5)) { if (heig<1.E+5 && heig>(-1.E+5)) {
Serial.print(" "); Serial.print(" ");
Serial.print((uint32_t)heig); Serial.print((uint32_t)heig);
@ -338,18 +340,18 @@ static void posrs41(const byte b[], uint32_t b_len, uint32_t p)
dir = X2C_DIVL(atang2(vn, ve),1.7453292519943E-2); dir = X2C_DIVL(atang2(vn, ve),1.7453292519943E-2);
if (dir<0.0) dir = 360.0+dir; if (dir<0.0) dir = 360.0+dir;
Serial.print(" "); Serial.print(" ");
si.hs = sqrt((float)(vn*vn+ve*ve))*3.6f; sonde.si()->hs = sqrt((float)(vn*vn+ve*ve))*3.6f;
Serial.print(si.hs); Serial.print(sonde.si()->hs);
Serial.print("km/h "); Serial.print("km/h ");
Serial.print(dir); Serial.print(dir);
Serial.print("deg "); Serial.print("deg ");
Serial.print((float)vu); Serial.print((float)vu);
si.vs = vu; sonde.si()->vs = vu;
Serial.print("m/s "); Serial.print("m/s ");
Serial.print(getcard16(b, b_len, p+18UL)&255UL); Serial.print(getcard16(b, b_len, p+18UL)&255UL);
Serial.print("Sats"); Serial.print("Sats");
si.hei = heig; sonde.si()->hei = heig;
si.validPos = true; sonde.si()->validPos = true;
} /* end posrs41() */ } /* end posrs41() */
@ -400,10 +402,10 @@ void 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);
strcpy(si.type, "RS41"); sonde.si()->type=STYPE_RS41;
strncpy(si.id, (const char *)(data+p+2), 8); strncpy(sonde.si()->id, (const char *)(data+p+2), 8);
si.id[8]=0; sonde.si()->id[8]=0;
si.validID=true; sonde.si()->validID=true;
} }
// TODO: some more data // TODO: some more data
break; break;
@ -463,14 +465,15 @@ int RS41::receiveFrame() {
sx1278.setPayloadLength(MAXLEN-8); // Expect 320-8 bytes or 518-8 bytes (8 byte header) sx1278.setPayloadLength(MAXLEN-8); // Expect 320-8 bytes or 518-8 bytes (8 byte header)
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE); sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
int e = sx1278.receivePacketTimeout(3000, data+8); int e = sx1278.receivePacketTimeout(1000, data+8);
if(e) { Serial.println("TIMEOUT"); return 1; } //if timeout... return 1 if(e) { Serial.println("TIMEOUT"); return RX_TIMEOUT; } //if timeout... return 1
for(int i=0; i<MAXLEN; i++) { data[i] = reverse(data[i]); } for(int i=0; i<MAXLEN; i++) { data[i] = reverse(data[i]); }
//printRaw(data, MAXLEN); //printRaw(data, MAXLEN);
for(int i=0; i<MAXLEN; i++) { data[i] = data[i] ^ scramble[i&0x3F]; } for(int i=0; i<MAXLEN; i++) { data[i] = data[i] ^ scramble[i&0x3F]; }
//printRaw(data, MAXLEN); //printRaw(data, MAXLEN);
decode41(data, MAXLEN); decode41(data, MAXLEN);
return RX_OK;
} }
RS41 rs41 = RS41(); RS41 rs41 = RS41();

Wyświetl plik

@ -0,0 +1,95 @@
#include "Scanner.h"
#include <SX1278FSK.h>
#include <U8x8lib.h>
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8;
#define CHANBW 25
#define SMOOTH 2
#define STARTF 400000000
#define NCHAN ((int)(6000/CHANBW))
int scanresult[NCHAN];
int scandisp[NCHAN/2];
#define PLOT_N 120
#define PLOT_MIN -220
#define PLOT_SCALE(x) (x<PLOT_MIN?0:(x-PLOT_MIN)/2)
const byte tilepatterns[9]={0,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF};
void Scanner::fillTiles(uint8_t *row, int value) {
for(int y=0; y<8; y++) {
int nbits = value - 8*(7-y);
if(nbits<0) { row[8*y]=0; continue; }
if(nbits>=8) { row[8*y]=255; continue; }
row[8*y] = tilepatterns[nbits];
}
}
/*
* There are 16*8 columns to plot, NPLOT must be lower than that
* currently, we use 120 * 50kHz channels
* There are 8*8 values to plot; MIN is bottom end,
*/
uint8_t tiles[16] = { 0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0, 1, 3, 7, 15, 31, 63, 127, 255};
void Scanner::plotResult()
{
uint8_t row[8*8];
for(int i=0; i<PLOT_N; i+=8) {
for(int j=0; j<8; j++) {
fillTiles(row+j, PLOT_SCALE(scandisp[i+j]));
}
for(int y=0; y<8; y++) {
u8x8.drawTile(i/8, y, 1, row+8*y);
}
}
}
void Scanner::scan()
{
#if 0
// Test only
for(int i=0; i<PLOT_N; i++) {
scandisp[i] = 30*sin(2*3.1415*i/50)-180;
}
return;
#endif
// Configure
sx1278.writeRegister(REG_PLL_HOP, 0x80); // FastHopOn
sx1278.setRxBandwidth(CHANBW*1000);
sx1278.writeRegister(REG_RSSI_CONFIG, SMOOTH&0x07);
sx1278.setFrequency(STARTF);
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
delay(5);
unsigned long start = millis();
uint32_t lastfrf=-1;
for(int i=0; i<NCHAN; i++) {
float freq = STARTF + 1000.0*i*CHANBW;
uint32_t frf = freq * 1.0 * (1<<19) / SX127X_CRYSTAL_FREQ;
if( (lastfrf>>16)!=(frf>>16) ) {
sx1278.writeRegister(REG_FRF_MSB, (frf&0xff0000)>>16);
}
if( ((lastfrf&0x00ff00)>>8) != ((frf&0x00ff00)>>8) ) {
sx1278.writeRegister(REG_FRF_MID, (frf&0x00ff00)>>8);
}
sx1278.writeRegister(REG_FRF_LSB, (frf&0x0000ff));
lastfrf = frf;
// Wait TS_HOP (20us) + TS_RSSI ( 2^(SMOOTH+1) / 4 / CHANBW us)
int wait = 20 + 1000*(1<<(SMOOTH+1))/4/CHANBW;
delayMicroseconds(wait);
int rssi = -(int)sx1278.readRegister(REG_RSSI_VALUE_FSK);
scanresult[i] = rssi;
}
unsigned long duration = millis()-start;
Serial.print("Scan time: ");
Serial.println(duration);
for(int i=0; i<NCHAN; i+=2) {
scandisp[i/2] = scanresult[i];
for(int j=1; j<2; j++) { if(scanresult[i+j]>scandisp[i/2]) scandisp[i/2] = scanresult[i+j]; }
Serial.print(scanresult[i]); Serial.print(", ");
if(((i+1)%32) == 0) Serial.println();
}
Serial.println("\n");
}
Scanner scanner = Scanner();

Wyświetl plik

@ -0,0 +1,24 @@
#ifndef _SCANNER_H
#define _SCANNER_H
#include <stdlib.h>
#include <stdint.h>
#include <Arduino.h>
#ifndef inttypes_h
#include <inttypes.h>
#endif
class Scanner
{
private:
void fillTiles(uint8_t *row, int value);
public:
void plotResult();
void scan(void);
};
extern Scanner scanner;
#endif

Wyświetl plik

@ -2,10 +2,13 @@
#include <U8g2lib.h> #include <U8g2lib.h>
#include "Sonde.h" #include "Sonde.h"
#include "RS41.h"
#include "DFM.h"
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8; extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8;
SondeInfo si = { "RS41", 403.450, "P1234567", true, 48.1234, 14.9876, 543, 3.97, -0.5, true, 120 }; //SondeInfo si = { STYPE_RS41, 403.450, "P1234567", true, 48.1234, 14.9876, 543, 3.97, -0.5, true, 120 };
const char *sondeTypeStr[5] = { "DFM6", "DFM9", "RS41" };
static unsigned char kmh_tiles[] U8X8_PROGMEM = { static unsigned char kmh_tiles[] U8X8_PROGMEM = {
0x1F, 0x04, 0x0A, 0x11, 0x00, 0x1F, 0x02, 0x04, 0x42, 0x3F, 0x10, 0x08, 0xFC, 0x22, 0x20, 0xF8 0x1F, 0x04, 0x0A, 0x11, 0x00, 0x1F, 0x02, 0x04, 0x42, 0x3F, 0x10, 0x08, 0xFC, 0x22, 0x20, 0xF8
@ -13,14 +16,108 @@ static unsigned char kmh_tiles[] U8X8_PROGMEM = {
static unsigned char ms_tiles[] U8X8_PROGMEM = { static unsigned char ms_tiles[] U8X8_PROGMEM = {
0x1F, 0x02, 0x04, 0x02, 0x1F, 0x40, 0x20, 0x10, 0x08, 0x04, 0x12, 0xA4, 0xA4, 0xA4, 0x40, 0x00 0x1F, 0x02, 0x04, 0x02, 0x1F, 0x40, 0x20, 0x10, 0x08, 0x04, 0x12, 0xA4, 0xA4, 0xA4, 0x40, 0x00
}; };
static unsigned char stattiles[4][4] = {
0x00, 0x00, 0x00, 0x00 ,
0x00, 0x10, 0x10, 0x00 ,
0x1F, 0x15, 0x15, 0x00 ,
0x00, 0x1F, 0x00, 0x00 };
byte myIP_tiles[8*10];
static const uint8_t font[10][5]={
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x42, 0x7F, 0x40, 0x00, // 1
0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x21, 0x41, 0x45, 0x4B, 0x31, // 3
0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
0x01, 0x01, 0x79, 0x05, 0x03, // 7
0x36, 0x49, 0x49, 0x49, 0x36, // 8
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) {
int tp = 0;
int len = strlen(ip);
for(int i=0; i<len; i++) {
if(ip[i]=='.') { myIP_tiles[tp++]=0x40; myIP_tiles[tp++]=0x00; }
else {
int idx = ip[i]-'0';
memcpy(myIP_tiles+tp, &font[idx], 5);
myIP_tiles[tp+5] = 0;
tp+=6;
}
}
while(tp<8*10) { myIP_tiles[tp++]=0; }
}
void Sonde::clearSonde() {
nSonde = 0;
}
void Sonde::addSonde(float frequency, SondeType type) {
if(nSonde>=MAXSONDE) {
Serial.println("Cannot add another sonde, MAXSONDE reached");
return;
}
sondeList[nSonde].type = type;
sondeList[nSonde].freq = frequency;
memcpy(sondeList[nSonde].rxStat, "\x00\x01\x2\x3\x2\x1\x1\x2\x0\x3\x0\x0\x1\x2\x3\x1\x0", 18);
nSonde++;
}
void Sonde::nextConfig() {
currentSonde++;
if(currentSonde>=nSonde) {
currentSonde=0;
}
setup();
}
SondeInfo *Sonde::si() {
return &sondeList[currentSonde];
}
void Sonde::setup() {
// Test only: setIP("123.456.789.012");
// update receiver config: TODO
Serial.print("Setting up receiver on channel ");
Serial.println(currentSonde);
switch(sondeList[currentSonde].type) {
case STYPE_RS41:
rs41.setup();
rs41.setFrequency(sondeList[currentSonde].freq * 1000000);
break;
case STYPE_DFM06:
case STYPE_DFM09:
dfm.setup( sondeList[currentSonde].type==STYPE_DFM06?0:1 );
dfm.setFrequency(sondeList[currentSonde].freq * 1000000);
break;
}
// Update display
//updateDisplayRXConfig();
//updateDisplay();
}
int Sonde::receiveFrame() {
int ret;
if(sondeList[currentSonde].type == STYPE_RS41) {
ret = rs41.receiveFrame();
} else {
ret = dfm.receiveFrame();
}
memmove(sonde.si()->rxStat+1, sonde.si()->rxStat, 17);
sonde.si()->rxStat[0] = ret==0 ? 3 : 1; // OK or Timeout; TODO: add error (2)
return ret; // 0: OK, 1: Timeuot, 2: Other error (TODO)
}
void Sonde::updateDisplayPos() { void Sonde::updateDisplayPos() {
char buf[16]; char buf[16];
u8x8.setFont(u8x8_font_7x14_1x2_r); u8x8.setFont(u8x8_font_7x14_1x2_r);
if(si.validPos) { if(si()->validPos) {
snprintf(buf, 16, "%2.5f", si.lat); snprintf(buf, 16, "%2.5f", si()->lat);
u8x8.drawString(0,2,buf); u8x8.drawString(0,2,buf);
snprintf(buf, 16, "%2.5f", si.lon); snprintf(buf, 16, "%2.5f", si()->lon);
u8x8.drawString(0,4,buf); u8x8.drawString(0,4,buf);
} else { } else {
u8x8.drawString(0,2,"<??> "); u8x8.drawString(0,2,"<??> ");
@ -31,17 +128,17 @@ void Sonde::updateDisplayPos() {
void Sonde::updateDisplayPos2() { void Sonde::updateDisplayPos2() {
char buf[16]; char buf[16];
u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.setFont(u8x8_font_chroma48medium8_r);
if(!si.validPos) { if(!si()->validPos) {
u8x8.drawString(10,2," "); u8x8.drawString(10,2," ");
u8x8.drawString(10,3," "); u8x8.drawString(10,3," ");
u8x8.drawString(10,4," "); u8x8.drawString(10,4," ");
return; return;
} }
snprintf(buf, 16, si.hei>999?"%5.0fm":"%3.1fm", si.hei); snprintf(buf, 16, si()->hei>999?"%5.0fm":"%3.1fm", si()->hei);
u8x8.drawString((10+6-strlen(buf)),2,buf); u8x8.drawString((10+6-strlen(buf)),2,buf);
snprintf(buf, 16, si.hs>99?"%3.0f":"%2.1f", si.hs); snprintf(buf, 16, si()->hs>99?"%3.0f":"%2.1f", si()->hs);
u8x8.drawString((10+4-strlen(buf)),3,buf); u8x8.drawString((10+4-strlen(buf)),3,buf);
snprintf(buf, 16, "%+2.1f", si.vs); snprintf(buf, 16, "%+2.1f", si()->vs);
u8x8.drawString((10+4-strlen(buf)),4,buf); u8x8.drawString((10+4-strlen(buf)),4,buf);
u8x8.drawTile(14,3,2,kmh_tiles); u8x8.drawTile(14,3,2,kmh_tiles);
u8x8.drawTile(14,4,2,ms_tiles); u8x8.drawTile(14,4,2,ms_tiles);
@ -49,8 +146,8 @@ void Sonde::updateDisplayPos2() {
void Sonde::updateDisplayID() { void Sonde::updateDisplayID() {
u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.setFont(u8x8_font_chroma48medium8_r);
if(si.validID) { if(si()->validID) {
u8x8.drawString(0,1, si.id); u8x8.drawString(0,1, si()->id);
} else { } else {
u8x8.drawString(0,1, "nnnnnnnn "); u8x8.drawString(0,1, "nnnnnnnn ");
} }
@ -59,19 +156,48 @@ 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 ", 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() {
uint8_t *stat = si()->rxStat;
for(int i=0; i<18; i+=2) {
uint8_t tile[8];
*(uint32_t *)(&tile[0]) = *(uint32_t *)(&(stattiles[stat[i]]));
*(uint32_t *)(&tile[4]) = *(uint32_t *)(&(stattiles[stat[i+1]]));
u8x8.drawTile(7+i/2, 6, 1, tile);
}
} }
void Sonde::updateDisplayRXConfig() { void Sonde::updateDisplayRXConfig() {
char buf[16]; char buf[16];
u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.drawString(0,0, si.type); u8x8.drawString(0,0, sondeTypeStr[si()->type]);
snprintf(buf, 16, "%3.3f MHz", si.freq); snprintf(buf, 16, "%3.3f MHz", si()->freq);
u8x8.drawString(5,0, buf); u8x8.drawString(5,0, buf);
} }
void Sonde::updateDisplayIP() {
u8x8.drawTile(6, 7, 10, myIP_tiles);
}
// Probing RS41
// 40x.xxx MHz
void Sonde::updateDisplayScanner() {
char buf[16];
u8x8.setFont(u8x8_font_7x14_1x2_r);
u8x8.drawString(0, 0, "Probing");
u8x8.drawString(8, 0, sondeTypeStr[si()->type]);
snprintf(buf, 16, "%3.3f MHz", si()->freq);
u8x8.drawString(0,3, buf);
updateDisplayIP();
}
void Sonde::updateDisplay() void Sonde::updateDisplay()
{ {
char buf[16]; char buf[16];
@ -80,6 +206,12 @@ void Sonde::updateDisplay()
updateDisplayPos(); updateDisplayPos();
updateDisplayPos2(); updateDisplayPos2();
updateDisplayRSSI(); updateDisplayRSSI();
updateStat();
updateDisplayIP();
}
void Sonde::clearDisplay() {
u8x8.clearDisplay();
} }
Sonde sonde = Sonde(); Sonde sonde = Sonde();

Wyświetl plik

@ -1,11 +1,18 @@
#ifndef Sonde_h #ifndef Sonde_h
#define Sonde_H #define Sonde_H
// RX_TIMEOUT: no header detected
// RX_ERROR: header detected, but data not decoded (crc error, etc.)
// RX_OK: header and data ok
enum RxResult { RX_OK, RX_TIMEOUT, RX_ERROR };
enum SondeType { STYPE_DFM06, STYPE_DFM09, STYPE_RS41 };
extern const char *sondeTypeStr[5];
typedef struct st_sondeinfo { typedef struct st_sondeinfo {
// receiver configuration // receiver configuration
char type[5]; SondeType type;
float freq; float freq;
// decoded ID // decoded ID
char id[10]; char id[10];
@ -16,23 +23,43 @@ 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];
} SondeInfo; } SondeInfo;
// rxState: 0=undef[empty] 1=timeout[.] 2=errro[E] 3=ok[1]
extern SondeInfo si;
#define MAXSONDE 10
class Sonde class Sonde
{ {
private: private:
int nSonde;
int currentSonde = 0;
SondeInfo sondeList[MAXSONDE+1];
public: public:
void clearSonde();
void addSonde(float frequency, SondeType type);
void nextConfig();
void setup();
int receiveFrame();
SondeInfo *si();
void updateDisplayPos(); void updateDisplayPos();
void updateDisplayPos2(); void updateDisplayPos2();
void updateDisplayID(); void updateDisplayID();
void updateDisplayRSSI(); void updateDisplayRSSI();
void updateDisplayRXConfig(); void updateDisplayRXConfig();
void updateStat();
void updateDisplayIP();
void updateDisplay(); void updateDisplay();
void updateDisplayScanner();
void clearDisplay();
void setIP(const char *ip);
}; };
extern Sonde sonde; extern Sonde sonde;