Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6978f1cccc |
@@ -1,4 +1,4 @@
|
|||||||
RadioSonde Version 0.9.0
|
RadioSonde Version 0.9.1
|
||||||
============================
|
============================
|
||||||
<img src="http://xavier.debert.free.fr/RS/TTGO.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO2.jpg" width="50%">
|
<img src="http://xavier.debert.free.fr/RS/TTGO.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO2.jpg" width="50%">
|
||||||
<img src="http://xavier.debert.free.fr/RS/TTGO3.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO4.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO5.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO6.jpg" width="50%">
|
<img src="http://xavier.debert.free.fr/RS/TTGO3.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO4.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO5.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO6.jpg" width="50%">
|
||||||
@@ -12,49 +12,57 @@
|
|||||||
Projet basé sur le travail de DL9RDZ
|
Projet basé sur le travail de DL9RDZ
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
Pour TTGO LORA 32 esp32 pico D4
|
Pour TTGO LORA 32 esp32 pico D4 <br>
|
||||||
Décodage de RadioSonde RS41 and DFM06/09 et M10
|
Décodage de RadioSonde RS41/92 and DFM06/09/17 et M10+/20
|
||||||
|
|
||||||
Attention à la version de votre TTGO!
|
Attention à la version de votre TTGO! <br>
|
||||||
vous devez modifier dans config.txt, le port de l'écran OLED
|
vous devez modifier dans config.txt, le port de l'écran OLED <br>
|
||||||
- TTGO v1: SDA=4 SCL=15, RST=16
|
- TTGO v1: SDA=4 SCL=15, RST=16 <br>
|
||||||
- TTGO v2: SDA=21 SCL=22, RST=16
|
- TTGO v2: SDA=21 SCL=22, RST=16
|
||||||
|
|
||||||
## Version en production 0.9.0 devel 0.9.1
|
## Version en production 0.9.1 devel 0.9.2
|
||||||
|
|
||||||
|
## 0.9.1
|
||||||
|
Corection RS41 <br>
|
||||||
|
Correction DFM 06/09 <br>
|
||||||
|
Add DFM17 <br>
|
||||||
|
Correction for all trame recived for M10 and M20 1000ms to 1512ms,<br>
|
||||||
|
Correction formulaire QRG, and end RS no save
|
||||||
|
|
||||||
## 0.9.0
|
## 0.9.0
|
||||||
Add M20
|
Add M20
|
||||||
|
|
||||||
## 0.8.8
|
## 0.8.8
|
||||||
|
|
||||||
Add M10+
|
Add M10+ <br>
|
||||||
Add Temps restant avant impacte au sol si 99: 0. 0 soit le balon de la sonde n a pas encore éclaté, ou les informations ne sont pas disponible actuellement
|
Add Temps restant avant impacte au sol si 99: 0. 0 soit le balon de la sonde n a pas encore éclaté, <br>
|
||||||
Add Test Buzzer au démarrage "Arche Perdu" Lol pour des chasseurs de sonde!
|
ou les informations ne sont pas disponible actuellement <br>
|
||||||
|
Add Test Buzzer au démarrage "Arche Perdu" Lol pour des chasseurs de sonde!<br>
|
||||||
Compatible Lilygo esp32 GPS inboard pin 34 Rx, 12 Tx
|
Compatible Lilygo esp32 GPS inboard pin 34 Rx, 12 Tx
|
||||||
|
|
||||||
## 0.8.7
|
## 0.8.7
|
||||||
|
|
||||||
correction bug Buzzer Off->On->Off
|
correction bug Buzzer Off->On->Off <br>
|
||||||
Add GainLNA RX SX1278FSK on Web config paramètre
|
Add GainLNA RX SX1278FSK on Web config paramètre <br>
|
||||||
Add update OTA Os + DataWeb
|
Add update OTA Os + DataWeb <br>
|
||||||
correction bugs sondmap.html
|
correction bugs sondmap.html <br>
|
||||||
correction text upgrade Os et DataWeb
|
correction text upgrade Os et DataWeb <br>
|
||||||
correction texte boussole S et N
|
correction texte boussole S et N <br>
|
||||||
correction bugs distance 4928Km si lat et lon =0 erroné
|
correction bugs distance 4928Km si lat et lon =0 erroné <br>
|
||||||
correction bugs fonction Vbat
|
correction bugs fonction Vbat <br>
|
||||||
Add Telemetry width export data.csv
|
Add Telemetry width export data.csv <br>
|
||||||
Suppression µSD incompatible avec pin SX1278FSK et SPI
|
Suppression µSD incompatible avec pin SX1278FSK et SPI <br>
|
||||||
Add transfert Telemetry To µSD on put SD automatic
|
Add transfert Telemetry To µSD on put SD automatic
|
||||||
|
|
||||||
## 0.8.5
|
## 0.8.5
|
||||||
|
|
||||||
Evolution majeur du système
|
Evolution majeur du système <br>
|
||||||
affichage du pourcentage de la batterie en mode scanning
|
affichage du pourcentage de la batterie en mode scanning <br>
|
||||||
création d'une fenetre Batterie, Boussole
|
création d'une fenetre Batterie, Boussole <br>
|
||||||
suppresion lib et code TFT
|
suppresion lib et code TFT <br>
|
||||||
création Azimute, elevation correction de Bugs majeur , mineur
|
création Azimute, elevation correction de Bugs majeur , mineur <br>
|
||||||
Ajout fonction Smetre, Buzzer, QTH, Gps on off ...
|
Ajout fonction Smetre, Buzzer, QTH, Gps on off ... <br>
|
||||||
mise à jour OTA
|
mise à jour OTA <br>
|
||||||
trop de modification pour toutes les expliciter!
|
trop de modification pour toutes les expliciter!
|
||||||
|
|
||||||
## 0.8.1
|
## 0.8.1
|
||||||
@@ -68,21 +76,26 @@ travail de refonte et réécriture du code
|
|||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
## Les Boutons optionnel à ajouter(souder)
|
## Les Boutons optionnel à ajouter(souder)
|
||||||
sur les GPIO 1002 et 1004
|
sur les GPIO 1002 et 1004 <br>
|
||||||
attention:
|
attention:
|
||||||
|
|
||||||
+3.3V--[ SW ]---GPIO----[ R1 ]---/ R1=10 ou 12KOhms
|
+3.3V--[ SW ]---GPIO----[ R1 ]---/ R1=10 ou 12KOhms
|
||||||
|
|
||||||
- appuie court <1.5 seconds
|
- appuie court <1.5 seconds <br>
|
||||||
- appuie double court 0.5 seconds
|
- appuie double court 0.5 seconds <br>
|
||||||
- appuie moyen 2-4 seconds
|
- appuie moyen 2-4 seconds <br>
|
||||||
- appuie long >5 seconds
|
- appuie long >5 seconds
|
||||||
|
|
||||||
|
## Buzzer optionnel à ajouter(souder)
|
||||||
|
sur les GPIO 25 ou 12 suivant le modèl
|
||||||
|
|
||||||
|
GPIO --[ BUZZER ]---/
|
||||||
|
|
||||||
## Wifi configuration
|
## Wifi configuration
|
||||||
|
|
||||||
Au démarrage, si aucune connexion possible au wifi paramètré, il monte un Wifi AP
|
Au démarrage, si aucune connexion possible au wifi paramètré, il monte un Wifi AP<br>
|
||||||
le SSID et mot de passe par défaut est: Radiosonde
|
le SSID et mot de passe par défaut est: <b>Radiosonde</b> <br>
|
||||||
en mode AP, il doit être en 192.168.4.1,
|
en mode AP, il doit être en 192.168.4.1, <br>
|
||||||
mais vous avez aussi la possibilité de mettre http://radiosonde.local dans n'importe quel Wifi
|
mais vous avez aussi la possibilité de mettre http://radiosonde.local dans n'importe quel Wifi
|
||||||
connecté.
|
connecté.
|
||||||
|
|
||||||
@@ -122,3 +135,141 @@ Xavier
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RadioSonde Version 0.9.1
|
||||||
|
============================
|
||||||
|
<img src="http://xavier.debert.free.fr/RS/TTGO.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO2.jpg" width="50%">
|
||||||
|
<img src="http://xavier.debert.free.fr/RS/TTGO3.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO4.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO5.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO6.jpg" width="50%">
|
||||||
|
<img src="http://xavier.debert.free.fr/RS/TTGO7.jpg" width="50%"><img src="http://xavier.debert.free.fr/RS/TTGO8.jpg" width="50%">
|
||||||
|
<img src="http://xavier.debert.free.fr/RS/Web4.png" width="20%"><img src="http://xavier.debert.free.fr/RS/Web.png" width="20%">
|
||||||
|
<img src="http://xavier.debert.free.fr/RS/Web3.png" width="20%"><img src="http://xavier.debert.free.fr/RS/Web2.png" width="20%">
|
||||||
|
<img src="http://xavier.debert.free.fr/RS/Web5.png" width="20%"><img src="http://xavier.debert.free.fr/RS/Web6.png" width="20%">
|
||||||
|
<img src="http://xavier.debert.free.fr/RS/Web7.png" width="20%">
|
||||||
|
|
||||||
|
|
||||||
|
Projet basé sur le travail de DL9RDZ
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Pour TTGO LORA 32 esp32 pico D4 <br>
|
||||||
|
Décodage de RadioSonde RS41/92 and DFM06/09/17 et M10+/20
|
||||||
|
|
||||||
|
Attention à la version de votre TTGO! <br>
|
||||||
|
vous devez modifier dans config.txt, le port de l'écran OLED <br>
|
||||||
|
- TTGO v1: SDA=4 SCL=15, RST=16 <br>
|
||||||
|
- TTGO v2: SDA=21 SCL=22, RST=16
|
||||||
|
|
||||||
|
## Version en production 0.9.1 devel 0.9.2
|
||||||
|
|
||||||
|
## 0.9.1
|
||||||
|
Corection RS41 <br>
|
||||||
|
Correction DFM 06/09 <br>
|
||||||
|
Add DFM17 <br>
|
||||||
|
Correction for all trame recived for M10 and M20 1000ms to 1512ms,<br>
|
||||||
|
Correction formulaire QRG, and end RS no save
|
||||||
|
|
||||||
|
## 0.9.0
|
||||||
|
Add M20
|
||||||
|
|
||||||
|
## 0.8.8
|
||||||
|
|
||||||
|
Add M10+ <br>
|
||||||
|
Add Temps restant avant impacte au sol si 99: 0. 0 soit le balon de la sonde n a pas encore éclaté, <br>
|
||||||
|
ou les informations ne sont pas disponible actuellement <br>
|
||||||
|
Add Test Buzzer au démarrage "Arche Perdu" Lol pour des chasseurs de sonde!<br>
|
||||||
|
Compatible Lilygo esp32 GPS inboard pin 34 Rx, 12 Tx
|
||||||
|
|
||||||
|
## 0.8.7
|
||||||
|
|
||||||
|
correction bug Buzzer Off->On->Off <br>
|
||||||
|
Add GainLNA RX SX1278FSK on Web config paramètre <br>
|
||||||
|
Add update OTA Os + DataWeb <br>
|
||||||
|
correction bugs sondmap.html <br>
|
||||||
|
correction text upgrade Os et DataWeb <br>
|
||||||
|
correction texte boussole S et N <br>
|
||||||
|
correction bugs distance 4928Km si lat et lon =0 erroné <br>
|
||||||
|
correction bugs fonction Vbat <br>
|
||||||
|
Add Telemetry width export data.csv <br>
|
||||||
|
Suppression µSD incompatible avec pin SX1278FSK et SPI <br>
|
||||||
|
Add transfert Telemetry To µSD on put SD automatic
|
||||||
|
|
||||||
|
## 0.8.5
|
||||||
|
|
||||||
|
Evolution majeur du système <br>
|
||||||
|
affichage du pourcentage de la batterie en mode scanning <br>
|
||||||
|
création d'une fenetre Batterie, Boussole <br>
|
||||||
|
suppresion lib et code TFT <br>
|
||||||
|
création Azimute, elevation correction de Bugs majeur , mineur <br>
|
||||||
|
Ajout fonction Smetre, Buzzer, QTH, Gps on off ... <br>
|
||||||
|
mise à jour OTA <br>
|
||||||
|
trop de modification pour toutes les expliciter!
|
||||||
|
|
||||||
|
## 0.8.1
|
||||||
|
|
||||||
|
modification de la partie Web
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
travail de refonte et réécriture du code
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Les Boutons optionnel à ajouter(souder)
|
||||||
|
sur les GPIO 1002 et 1004 <br>
|
||||||
|
attention:
|
||||||
|
|
||||||
|
+3.3V--[ SW ]---GPIO----[ R1 ]---/ R1=10 ou 12KOhms
|
||||||
|
|
||||||
|
- appuie court <1.5 seconds <br>
|
||||||
|
- appuie double court 0.5 seconds <br>
|
||||||
|
- appuie moyen 2-4 seconds <br>
|
||||||
|
- appuie long >5 seconds
|
||||||
|
|
||||||
|
## Buzzer optionnel à ajouter(souder)
|
||||||
|
sur les GPIO 25 ou 12 suivant le modèl
|
||||||
|
|
||||||
|
GPIO --[ BUZZER ]---/
|
||||||
|
|
||||||
|
## Wifi configuration
|
||||||
|
|
||||||
|
Au démarrage, si aucune connexion possible au wifi paramètré, il monte un Wifi AP<br>
|
||||||
|
le SSID et mot de passe par défaut est: <b>Radiosonde</b> <br>
|
||||||
|
en mode AP, il doit être en 192.168.4.1, <br>
|
||||||
|
mais vous avez aussi la possibilité de mettre http://radiosonde.local dans n'importe quel Wifi
|
||||||
|
connecté.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Mode Scanne
|
||||||
|
|
||||||
|
Le fichier qrg.txt contient la liste par défaut des cannaux.
|
||||||
|
pour y configurer les noms, fréquences et mode [M=M10, 6=DFM06, 9=DFM09 et 4=RS41]
|
||||||
|
|
||||||
|
|
||||||
|
## Mode Réception
|
||||||
|
|
||||||
|
En réception, une seul fréquence est décodé, les infos de la sonde (ID, GPS, RSSI, ...)
|
||||||
|
seront affichées dans plusieur fenetre à choisir ( 0 à 6) à configurer dans la page Web
|
||||||
|
rubrique config.
|
||||||
|
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
|
||||||
|
|
||||||
|
## Mode Analyseur
|
||||||
|
|
||||||
|
Le mode analyseur de spectre (400..406 MHz) est affiché (chaque ligne == 50 kHz)
|
||||||
|
Pour les cartes TTGO sans bouton configurable, il y a un nouveau paramètre dans config.txt:
|
||||||
|
- spectrum=10 // 0=off / 1-99 nombre de seconds pour afficher l'analyseur
|
||||||
|
- timer=1 // 0=off / 1= afficher le compte à rebours du spectre dans l'affichage du spectre
|
||||||
|
- marker=1 // 0=off / 1= afficher la fréquence dans l'affichage du spectre
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
voir Setup.md pour l'installation!
|
||||||
|
|
||||||
|
73
|
||||||
|
Xavier
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
//#include <U8x8lib.h>
|
|
||||||
//#include <U8g2lib.h>
|
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
#include <ESPmDNS.h>
|
#include <ESPmDNS.h>
|
||||||
@@ -24,6 +22,7 @@
|
|||||||
|
|
||||||
#include "spiffs_sd.h"
|
#include "spiffs_sd.h"
|
||||||
|
|
||||||
|
|
||||||
int e;
|
int e;
|
||||||
enum MainState { ST_DECODER, ST_SPECTRUM, ST_WIFISCAN, ST_UPDATE, ST_TOUCHCALIB };
|
enum MainState { ST_DECODER, ST_SPECTRUM, ST_WIFISCAN, ST_UPDATE, ST_TOUCHCALIB };
|
||||||
static MainState mainState = ST_WIFISCAN; // ST_WIFISCAN;
|
static MainState mainState = ST_WIFISCAN; // ST_WIFISCAN;
|
||||||
@@ -42,15 +41,7 @@ String updateBinM = "/RS/radiosonde/update.ino.bin";
|
|||||||
String updateBinD = "/RS/radiosondedevel/update.ino.bin";
|
String updateBinD = "/RS/radiosondedevel/update.ino.bin";
|
||||||
String *updateBin = &updateBinM;
|
String *updateBin = &updateBinM;
|
||||||
|
|
||||||
String updateDataWeb = "/RS/dataweb/index.html.txt";
|
String updateDataWeb = "/RS/dataweb/data.tar";
|
||||||
String updateDataWeb2 = "/RS/dataweb/sondemap.html.txt";
|
|
||||||
String updateDataWeb3 = "/RS/dataweb/config.txt";
|
|
||||||
String updateDataWeb4 = "/RS/dataweb/screens.txt";
|
|
||||||
String updateDataWeb5 = "/RS/dataweb/style.css.txt";
|
|
||||||
String updateDataWeb6 = "/RS/dataweb/qrg.txt";
|
|
||||||
String updateDataWeb7 = "/RS/dataweb/networks.txt";
|
|
||||||
String updateDataWeb8 = "/RS/dataweb/fontawesome-webfont.eot.txt";
|
|
||||||
String updateDataWeb9 = "/RS/dataweb/fontawesome-webfont.woff.txt";
|
|
||||||
|
|
||||||
#define LOCALUDPPORT 9002
|
#define LOCALUDPPORT 9002
|
||||||
|
|
||||||
@@ -164,9 +155,10 @@ void setupChannelList() {
|
|||||||
sonde.clearSonde();
|
sonde.clearSonde();
|
||||||
Serial.println("Reading channel config:");
|
Serial.println("Reading channel config:");
|
||||||
while (file.available()) {
|
while (file.available()) {
|
||||||
String line = readLine(file); //file.readStringUntil('\n');
|
//String line = readLine(file); //file.readStringUntil('\n');
|
||||||
|
String line = file.readStringUntil('\n');
|
||||||
String sitename;
|
String sitename;
|
||||||
if (!file.available()) break;
|
//if (!file.available()) break;
|
||||||
if (line[0] == '#') continue;
|
if (line[0] == '#') continue;
|
||||||
char *space = strchr(line.c_str(), ' ');
|
char *space = strchr(line.c_str(), ' ');
|
||||||
if (!space) continue;
|
if (!space) continue;
|
||||||
@@ -184,6 +176,9 @@ void setupChannelList() {
|
|||||||
else if (space[1] == '6') {
|
else if (space[1] == '6') {
|
||||||
type = STYPE_DFM06;
|
type = STYPE_DFM06;
|
||||||
}
|
}
|
||||||
|
else if (space[1] == 'D') {
|
||||||
|
type = STYPE_DFM;
|
||||||
|
}
|
||||||
else if (space[1] == 'M') {
|
else if (space[1] == 'M') {
|
||||||
type = STYPE_M10;
|
type = STYPE_M10;
|
||||||
}
|
}
|
||||||
@@ -208,25 +203,55 @@ void setupChannelList() {
|
|||||||
|
|
||||||
const char *createQRGForm() {
|
const char *createQRGForm() {
|
||||||
char *ptr = message;
|
char *ptr = message;
|
||||||
strcpy(ptr, "<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"></head><body><form action=\"qrg.html\" method=\"post\"><table><tr><th>ID</th><th>Active</th><th>Freq</th><th>Launchsite</th><th>Mode</th></tr>");
|
strcpy(ptr, "<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">");
|
||||||
|
strcat(ptr, "<script type=\"text/javascript\">"
|
||||||
|
"let stypes=new Map();"
|
||||||
|
"stypes.set('4', 'RS41');"
|
||||||
|
"stypes.set('R', 'RS92');"
|
||||||
|
"stypes.set('9', 'DFM9');"
|
||||||
|
"stypes.set('6', 'DFM6');"
|
||||||
|
"stypes.set('D', 'DFM All');"
|
||||||
|
"stypes.set('M', 'M10');"
|
||||||
|
"stypes.set('2', 'M20');"
|
||||||
|
"function prep() {"
|
||||||
|
" var stlist=document.querySelectorAll(\"input.stype\");"
|
||||||
|
" for(txt of stlist){"
|
||||||
|
" var val=txt.getAttribute('value'); var nam=txt.getAttribute('name'); "
|
||||||
|
" var sel=document.createElement('select');"
|
||||||
|
" sel.setAttribute('name',nam);"
|
||||||
|
" for(stype of stypes) { "
|
||||||
|
" var opt=document.createElement('option');"
|
||||||
|
" opt.value=stype[0];"
|
||||||
|
" opt.innerHTML=stype[1];"
|
||||||
|
" if(stype[0]==val) { opt.setAttribute('selected','selected'); }"
|
||||||
|
" sel.appendChild(opt);"
|
||||||
|
" } txt.replaceWith(sel); } } "
|
||||||
|
" window.onload = prep; "
|
||||||
|
"</script>");
|
||||||
|
|
||||||
|
strcat(ptr, "</head><body><form action=\"qrg.html\" method=\"post\"><table><tr><th>ID</th><th>Active</th><th>Freq</th><th>Launchsite</th><th>Mode</th></tr>");
|
||||||
for (int i = 0; i < sonde.config.maxsonde; i++) {
|
for (int i = 0; i < sonde.config.maxsonde; i++) {
|
||||||
String s = sondeTypeSelect(i >= sonde.nSonde ? 2 : sonde.sondeList[i].type);
|
//String s = sondeTypeSelect(i >= sonde.nSonde ? 2 : sonde.sondeList[i].type);
|
||||||
String site = sonde.sondeList[i].launchsite;
|
String site = sonde.sondeList[i].launchsite;
|
||||||
sprintf(ptr + strlen(ptr), "<tr><td>%d</td><td><input name=\"A%d\" type=\"checkbox\" %s/></td>"
|
sprintf(ptr + strlen(ptr), "<tr><td>%d</td><td><input name=\"A%d\" type=\"checkbox\" %s/></td>"
|
||||||
"<td><input name=\"F%d\" type=\"text\" value=\"%3.3f\"></td>"
|
"<td><input name=\"F%d\" type=\"text\" value=\"%3.3f\"></td>"
|
||||||
"<td><input name=\"S%d\" type=\"text\" value=\"%s\"></td>"
|
"<td><input name=\"S%d\" type=\"text\" value=\"%s\"></td>"
|
||||||
"<td><select name=\"T%d\">%s</select></td>",
|
//"<td><select name=\"T%d\">%s</select></td>",
|
||||||
|
"<td><input class='stype' name='T%d' value='%c'>",
|
||||||
i + 1,
|
i + 1,
|
||||||
i + 1, (i < sonde.nSonde && sonde.sondeList[i].active) ? "checked" : "",
|
i + 1, (i < sonde.nSonde && sonde.sondeList[i].active) ? "checked" : "",
|
||||||
i + 1, i >= sonde.nSonde ? 400.000 : sonde.sondeList[i].freq,
|
i + 1, i >= sonde.nSonde ? 400.000 : sonde.sondeList[i].freq,
|
||||||
i + 1, i >= sonde.nSonde ? " " : sonde.sondeList[i].launchsite,
|
i + 1, i >= sonde.nSonde ? " " : sonde.sondeList[i].launchsite,
|
||||||
i + 1, s.c_str());
|
i + 1, i >= sonde.nSonde ? 2 : sondeTypeChar[sonde.sondeList[i].type] );
|
||||||
|
//i + 1, s.c_str());
|
||||||
}
|
}
|
||||||
strcat(ptr, "</table><input type=\"submit\" value=\"Update\"/></form></body></html>");
|
strcat(ptr, "</table><input type=\"submit\" value=\"Update\"/></form></body></html>");
|
||||||
Serial.printf("QRG form: size=%d bytes\n",strlen(message));
|
Serial.printf("QRG form: size=%d bytes\n", strlen(message));
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char *handleQRGPost(AsyncWebServerRequest *request) {
|
const char *handleQRGPost(AsyncWebServerRequest *request) {
|
||||||
char label[10];
|
char label[10];
|
||||||
// parameters: a_i, f_1, t_i (active/frequency/type)
|
// parameters: a_i, f_1, t_i (active/frequency/type)
|
||||||
@@ -263,7 +288,7 @@ const char *handleQRGPost(AsyncWebServerRequest *request) {
|
|||||||
const char *tstr = tstring.c_str();
|
const char *tstr = tstring.c_str();
|
||||||
const char *sstr = sstring.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);
|
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[1] == '1' ? 'M' : tstr[1] == '2' ? '2' : tstr[3]); // a bit ugly
|
char typech = tstr[0];
|
||||||
file.printf("%3.3f %c %c %s\n", atof(fstr), typech, active ? '+' : '-', sstr);
|
file.printf("%3.3f %c %c %s\n", atof(fstr), typech, active ? '+' : '-', sstr);
|
||||||
}
|
}
|
||||||
file.close();
|
file.close();
|
||||||
@@ -313,7 +338,6 @@ void setupWifiList() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *createWIFIForm() {
|
const char *createWIFIForm() {
|
||||||
char *ptr = message;
|
char *ptr = message;
|
||||||
char tmp[4];
|
char tmp[4];
|
||||||
@@ -377,7 +401,7 @@ void addSondeStatus(char *ptr, int 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", s->freq, sondeTypeStr[s->type],
|
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 : "<?""?>");
|
s->validID ? s->id : "<?""?>");
|
||||||
if (s->validID && (s->type == STYPE_DFM06 || s->type == STYPE_DFM09 || s->type == STYPE_M10 || s->type == STYPE_M20)) {
|
if (s->validID && (s->type == STYPE_DFM || s->type == STYPE_DFM06 || s->type == STYPE_DFM09 || s->type == STYPE_M10 || s->type == STYPE_M20)) {
|
||||||
sprintf(ptr + strlen(ptr), " (ser: %s)", s->ser);
|
sprintf(ptr + strlen(ptr), " (ser: %s)", s->ser);
|
||||||
}
|
}
|
||||||
sprintf(ptr + strlen(ptr), "</td></tr><tr><td>QTHSonde: %.6f,%.6f h=%.0fm</td></tr>\n", s->lat, s->lon, s->alt);
|
sprintf(ptr + strlen(ptr), "</td></tr><tr><td>QTHSonde: %.6f,%.6f h=%.0fm</td></tr>\n", s->lat, s->lon, s->alt);
|
||||||
@@ -390,9 +414,11 @@ void addSondeStatus(char *ptr, int i)
|
|||||||
sprintf(ptr + strlen(ptr), "<tr><td>Burst-KT=%d Launch-KT=%d Countdown=%d (vor %ds)</td></tr>\n",
|
sprintf(ptr + strlen(ptr), "<tr><td>Burst-KT=%d Launch-KT=%d Countdown=%d (vor %ds)</td></tr>\n",
|
||||||
s->burstKT, s->launchKT, s->countKT, ((uint16_t)s->frame - s->crefKT));
|
s->burstKT, s->launchKT, s->countKT, ((uint16_t)s->frame - s->crefKT));
|
||||||
}
|
}
|
||||||
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>");
|
||||||
|
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://www.google.fr/maps/dir//%.6f;%.6f\">G-MAPS</a> - ", s->lat, s->lon);
|
||||||
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://tracker.sondehub.org/?sondehub=1#!mt=osm&mz=8&qm=6_hours&mc=%.6f,%.6f&q=RS_%s\">Sondehub</a> - ", s->lat, s->lon, s->id);
|
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://tracker.sondehub.org/?sondehub=1#!mt=osm&mz=8&qm=6_hours&mc=%.6f,%.6f&q=RS_%s\">Sondehub</a> - ", s->lat, s->lon, 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);
|
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://www.openstreetmap.org/?mlat=%.6f&mlon=%.6f&zoom=14\">OSM</a> - ", s->lat, s->lon);
|
||||||
|
sprintf(ptr + strlen(ptr), "<a target=\"_empty\" href=\"https://www.google.com/maps/search/?api=1&query=%.6f,%.6f\">Google</a></td></tr>", s->lat, s->lon);
|
||||||
strcat(ptr, "</table><p/>\n");
|
strcat(ptr, "</table><p/>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1106,7 +1132,11 @@ char buffer[85];
|
|||||||
MicroNMEA nmea(buffer, sizeof(buffer));
|
MicroNMEA nmea(buffer, sizeof(buffer));
|
||||||
|
|
||||||
int lastCourse = 0;
|
int lastCourse = 0;
|
||||||
void unkHandler(const MicroNMEA& nmea) {
|
|
||||||
|
/// Arrg. MicroNMEA changes type definition... so lets auto-infer type
|
||||||
|
template<typename T>
|
||||||
|
//void unkHandler(const MicroNMEA& nmea) {
|
||||||
|
void unkHandler(T nmea) {
|
||||||
if (strcmp(nmea.getMessageID(), "VTG") == 0) {
|
if (strcmp(nmea.getMessageID(), "VTG") == 0) {
|
||||||
const char *s = nmea.getSentence();
|
const char *s = nmea.getSentence();
|
||||||
while (*s && *s != ',') s++;
|
while (*s && *s != ',') s++;
|
||||||
@@ -1116,6 +1146,7 @@ void unkHandler(const MicroNMEA& nmea) {
|
|||||||
Serial.printf("Course update: %d\n", lastCourse);
|
Serial.printf("Course update: %d\n", lastCourse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpsTask(void *parameter) {
|
void gpsTask(void *parameter) {
|
||||||
nmea.setUnknownSentenceHandler(unkHandler);
|
nmea.setUnknownSentenceHandler(unkHandler);
|
||||||
|
|
||||||
@@ -1139,10 +1170,31 @@ void gpsTask(void *parameter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define UBX_SYNCH_1 0xB5
|
||||||
|
#define UBX_SYNCH_2 0x62
|
||||||
|
uint8_t ubx_set9k6[]={UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x8F};
|
||||||
|
uint8_t ubx_factorydef[]={UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x09, 13, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0x17, 0x8A };
|
||||||
|
|
||||||
void initGPS() {
|
void initGPS() {
|
||||||
if (sonde.config.gps_rxd < 0) return; // GPS disabled
|
if (sonde.config.gps_rxd < 0) return; // GPS disabled
|
||||||
Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
if (sonde.config.gps_txd >= 0) { // TX enable, thus try setting baud to 9600 and do a factory reset
|
||||||
|
Serial.println("Trying to reset GPS...");
|
||||||
|
Serial2.begin(115200, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
Serial2.write(ubx_set9k6, sizeof(ubx_set9k6));
|
||||||
|
delay(100);
|
||||||
|
Serial2.begin(38400, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
Serial2.write(ubx_set9k6, sizeof(ubx_set9k6));
|
||||||
|
delay(100);
|
||||||
|
Serial2.begin(19200, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
Serial2.write(ubx_set9k6, sizeof(ubx_set9k6));
|
||||||
|
delay(100);
|
||||||
|
Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
Serial2.write(ubx_factorydef, sizeof(ubx_factorydef));
|
||||||
|
delay(1000);
|
||||||
|
} else {
|
||||||
|
Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
}
|
||||||
xTaskCreate( gpsTask, "gpsTask",
|
xTaskCreate( gpsTask, "gpsTask",
|
||||||
5000, /* stack size */
|
5000, /* stack size */
|
||||||
NULL, /* paramter */
|
NULL, /* paramter */
|
||||||
@@ -1460,6 +1512,7 @@ void setup()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Serial.println("Reading initial configuration");
|
Serial.println("Reading initial configuration");
|
||||||
setupConfigData(); // configuration must be read first due to OLED ports!!!
|
setupConfigData(); // configuration must be read first due to OLED ports!!!
|
||||||
|
|
||||||
@@ -1666,10 +1719,10 @@ const int melodie[][3] = { {4, 2, 2}, {5, 2, 1}, {7, 2, 3}, {0, 3, 6},
|
|||||||
setupChannelList();
|
setupChannelList();
|
||||||
#if 0
|
#if 0
|
||||||
sonde.clearSonde();
|
sonde.clearSonde();
|
||||||
sonde.addSonde(402.700, STYPE_RS41);
|
sonde.addSonde(402.800, STYPE_RS41);
|
||||||
sonde.addSonde(405.700, STYPE_RS41);
|
sonde.addSonde(402.000, STYPE_M10);
|
||||||
sonde.addSonde(405.900, STYPE_RS41);
|
sonde.addSonde(404.800, STYPE_RS41);
|
||||||
sonde.addSonde(403.450, STYPE_DFM09);
|
sonde.addSonde(403.000, STYPE_DFM09);
|
||||||
Serial.println("No channel config file, using defaults!");
|
Serial.println("No channel config file, using defaults!");
|
||||||
Serial.println();
|
Serial.println();
|
||||||
#endif
|
#endif
|
||||||
@@ -2420,28 +2473,14 @@ void execOTA() {
|
|||||||
// execOTA();
|
// execOTA();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
//ICI Update Data
|
//ICI Update Data
|
||||||
/*
|
|
||||||
// Update DATAWeb!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
// Update DATAWeb!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
//Data1 index.html
|
//Data data.tar
|
||||||
updatedataweb(updateHost,updatePort,updateDataWeb,"index.html");
|
updatedataweb(updateHost,updatePort,updateDataWeb,"index.html");
|
||||||
//Data2 sondemap.html
|
*/
|
||||||
updatedataweb(updateHost,updatePort,updateDataWeb2,"sondemap.html");
|
|
||||||
//Data3 config.txt
|
|
||||||
updatedataweb(updateHost,updatePort,updateDataWeb3,"config.txt");
|
|
||||||
//Data4 screens.txt
|
|
||||||
updatedataweb(updateHost,updatePort,updateDataWeb4,"screens.txt");
|
|
||||||
//Data5 styles.css
|
|
||||||
updatedataweb(updateHost,updatePort,updateDataWeb5,"style.css");
|
|
||||||
//Data6 qrg.txt
|
|
||||||
updatedataweb(updateHost,updatePort,updateDataWeb6,"qrg.txt");
|
|
||||||
//Data7 networks.txt
|
|
||||||
updatedataweb(updateHost,updatePort,updateDataWeb7,"networks.txt");
|
|
||||||
//Data8 fontawesome-webfont.eot
|
|
||||||
updatedataweb(updateHost,updatePort,updateDataWeb8,"fontawesome-webfont.eot");
|
|
||||||
//Data9 fontawesome-webfont.eot
|
|
||||||
updatedataweb(updateHost,updatePort,updateDataWeb9,"fontawesome-webfont.woff");
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (Update.end()) {
|
if (Update.end()) {
|
||||||
Serial.println("OTA done!");
|
Serial.println("OTA done!");
|
||||||
@@ -2528,6 +2567,8 @@ void updatedataweb(String host, int port, String dataweb, String fichier){
|
|||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
client.flush();
|
client.flush();
|
||||||
|
//Untar data.tar
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ dfm.rxbw=10400
|
|||||||
# data not sanitized / quality checked, outliers not filtered out
|
# data not sanitized / quality checked, outliers not filtered out
|
||||||
axudp.active=1
|
axudp.active=1
|
||||||
axudp.host=fra1od.fr.to
|
axudp.host=fra1od.fr.to
|
||||||
axudp.port=14580
|
axudp.port=20350
|
||||||
axudp.symbol=/O
|
axudp.symbol=/O
|
||||||
axudp.highrate=1
|
axudp.highrate=1
|
||||||
axudp.idformat=0
|
axudp.idformat=0
|
||||||
@@ -99,9 +99,9 @@ axudp.idformat=0
|
|||||||
# maybe some time in the future
|
# maybe some time in the future
|
||||||
#-------------------------------#
|
#-------------------------------#
|
||||||
# currently simply not implemented, no need to put anything here anyway
|
# currently simply not implemented, no need to put anything here anyway
|
||||||
tcp.active=0
|
tcp.active=1
|
||||||
tcp.host=radiosondy.info
|
tcp.host=fra1od.fr.to
|
||||||
tcp.port=14590
|
tcp.port=14580
|
||||||
tcp.symbol=/O
|
tcp.symbol=/O
|
||||||
tcp.highrate=20
|
tcp.highrate=20
|
||||||
tcp.idformat=0
|
tcp.idformat=0
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
<br>
|
<br>
|
||||||
Autodetect info: %AUTODETECT_INFO%<br>
|
Autodetect info: %AUTODETECT_INFO%<br>
|
||||||
<br>
|
<br>
|
||||||
CopyLeft 2020 Modifier par <a href="http://openpmr.cla.fr">FRS2013</a><br>
|
CopyLeft 2020 Modifier par <a href="http://openpmr.cla.fr">FRS2013</a> & Vigor<br>
|
||||||
Licence GNU GPL <a href="https://www.gnu.org/licenses/gpl-2.0.txt">https://www.gnu.org/licenses/gpl-2.0.txt</a>
|
Licence GNU GPL <a href="https://www.gnu.org/licenses/gpl-2.0.txt">https://www.gnu.org/licenses/gpl-2.0.txt</a>
|
||||||
for details
|
for details
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Frequency in Mhz (format nnn.nnn)
|
# Frequency in Mhz (format nnn.nnn)
|
||||||
# Type (4=RS41, R=RS92, 6=DFM normal, DFM-06, 9=DFM inverted, DFM-09, M=M10, 2=M20)
|
# Type (4=RS41, R=RS92, 6=DFM normal, DFM-06, 9=DFM inverted, DFM-09, D=DFM, M=M10, 2=M20)
|
||||||
#
|
#
|
||||||
400.000 9 + Test(FR)
|
400.000 9 + Test(FR)
|
||||||
401.500 4 - Santander(ES)
|
401.500 4 - Santander(ES)
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
const char *version_name = "RadioSonde";
|
const char *version_name = "RadioSonde";
|
||||||
const char *version_id = "0.9.0";
|
const char *version_id = "0.9.1";
|
||||||
//const int SPIFFS_MAJOR=3;
|
|
||||||
//const int SPIFFS_MINOR=5;
|
|
||||||
|
|||||||
@@ -1,347 +0,0 @@
|
|||||||
|
|
||||||
/* DFM decoder functions */
|
|
||||||
#include "DFM.h"
|
|
||||||
#include "SX1278FSK.h"
|
|
||||||
#include "Sonde.h"
|
|
||||||
|
|
||||||
#define DFM_DEBUG 1
|
|
||||||
|
|
||||||
#if DFM_DEBUG
|
|
||||||
#define DFM_DBG(x) x
|
|
||||||
#else
|
|
||||||
#define DFM_DBG(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int DFM::setup(float frequency, int inv)
|
|
||||||
{
|
|
||||||
inverse = inv;
|
|
||||||
#if DFM_DEBUG
|
|
||||||
Serial.printf("Setup sx1278 for DFM sonde (inv=%d)\n",inv);
|
|
||||||
#endif
|
|
||||||
if(sx1278.ON()!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setFSK()!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting FSM mode FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setBitrate(2500)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting bitrate 2500bit/s FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if DFM_DEBUG
|
|
||||||
float br = sx1278.getBitrate();
|
|
||||||
Serial.print("Exact bitrate is ");
|
|
||||||
Serial.println(br);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(sx1278.setAFCBandwidth(sonde.config.dfm.agcbw)!=0) {
|
|
||||||
DFM_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.dfm.agcbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setRxBandwidth(sonde.config.dfm.rxbw)!=0) {
|
|
||||||
DFM_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.dfm.rxbw));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
|
||||||
if(sx1278.setRxConf(0x1E)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting RX Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// Set autostart_RX to 01, preamble 0, SYNC detect==on, syncsize=3 (==4 byte
|
|
||||||
//char header[] = "0110.0101 0110.0110 1010.0101 1010.1010";
|
|
||||||
|
|
||||||
const char *SYNC=inverse?"\x9A\x99\x5A\x55":"\x65\x66\xA5\xAA";
|
|
||||||
if(sx1278.setSyncConf(0x53, 4, (const uint8_t *)SYNC)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting SYNC Config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(sx1278.setPreambleDetect(0xA8)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Packet config 1: fixed len, mancecer, no crc, no address filter
|
|
||||||
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
|
||||||
if(sx1278.setPacketConfig(0x28, 0x40)!=0) {
|
|
||||||
DFM_DBG(Serial.println("Setting Packet config FAILED"));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
Serial.print("DFM: setting RX frequency to ");
|
|
||||||
Serial.println(frequency);
|
|
||||||
|
|
||||||
int retval = sx1278.setFrequency(frequency);
|
|
||||||
sx1278.clearIRQFlags();
|
|
||||||
DFM_DBG(Serial.println("Setting SX1278 config for DFM finished\n"); Serial.println());
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define bitpick(value,bitpos) (((value)>>(7-(bitpos)))&0x01)
|
|
||||||
// Input: str: packed data, MSB first
|
|
||||||
void DFM::deinterleave(uint8_t *str, int L, uint8_t *block) {
|
|
||||||
int i, j;
|
|
||||||
for (j = 0; j < B; j++) { // L = 7 (CFG), 13 (DAT1, DAT2)
|
|
||||||
for (i = 0; i < L; i++) {
|
|
||||||
block[B*i+j] = bitpick( str[(L*j+i)/8], (L*j+i)&7 )?0:1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t DFM::bits2val(const uint8_t *bits, int len) {
|
|
||||||
uint32_t val = 0;
|
|
||||||
for (int j = 0; j < len; j++) {
|
|
||||||
val |= (bits[j] << (len-1-j));
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error correction for hamming code
|
|
||||||
// returns 0: ok >0: 1 error was corrected -1: uncorrectable error
|
|
||||||
int DFM::check(uint8_t code[8]) {
|
|
||||||
int i, j;
|
|
||||||
uint32_t synval = 0;
|
|
||||||
uint8_t syndrom[4];
|
|
||||||
int ret=0;
|
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
syndrom[i] = 0;
|
|
||||||
for (j = 0; j < 8; j++) {
|
|
||||||
syndrom[i] ^= H[i][j] & code[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
synval = bits2val(syndrom, 4);
|
|
||||||
if (synval) {
|
|
||||||
ret = -1;
|
|
||||||
for (j = 0; j < 8; j++) { // 1-bit-error
|
|
||||||
if (synval == He[j]) { // reicht auf databits zu pruefen, d.h.
|
|
||||||
ret = j+1; // (systematischer Code) He[0..3]
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else ret = 0;
|
|
||||||
if (ret > 0) code[ret-1] ^= 0x1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extended (8,4) Hamming code
|
|
||||||
// Return number of corrected bits, -1 if uncorrectable error
|
|
||||||
int DFM::hamming(uint8_t *ham, int L, uint8_t *sym) {
|
|
||||||
int i, j;
|
|
||||||
int ret = 0; // DFM: length L = 7 or 13
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
// systematic Hamming code: copy bits 0..3
|
|
||||||
for (j = 0; j < 4; j++) {
|
|
||||||
sym[4*i+j] = ham[8*i+j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFM::DFM() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void DFM::printRaw(const char *label, int len, int ret, const uint8_t *data)
|
|
||||||
{
|
|
||||||
Serial.print(label); Serial.print("(");
|
|
||||||
Serial.print(ret);
|
|
||||||
Serial.print("):");
|
|
||||||
int i;
|
|
||||||
for(i=0; i<len/2; i++) {
|
|
||||||
char str[10];
|
|
||||||
snprintf(str, 10, "%02X", data[i]);
|
|
||||||
Serial.print(str);
|
|
||||||
}
|
|
||||||
Serial.print(data[i]&0x0F, HEX);
|
|
||||||
Serial.print(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
void DFM::decodeCFG(uint8_t *cfg)
|
|
||||||
{
|
|
||||||
static int lowid, highid, idgood=0, type=0;
|
|
||||||
if((cfg[0]>>4)==0x06 && type==0) { // DFM-6 ID
|
|
||||||
lowid = ((cfg[0]&0x0F)<<20) | (cfg[1]<<12) | (cfg[2]<<4) | (cfg[3]&0x0f);
|
|
||||||
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
|
|
||||||
type=9;
|
|
||||||
if(cfg[3]==1) {
|
|
||||||
lowid = (cfg[1]<<8) | cfg[2];
|
|
||||||
idgood |= 1;
|
|
||||||
} else {
|
|
||||||
highid = (cfg[1]<<8) | cfg[2];
|
|
||||||
idgood |= 2;
|
|
||||||
}
|
|
||||||
if(idgood==3) {
|
|
||||||
uint32_t dfmid = (highid<<16) | lowid;
|
|
||||||
Serial.print("DFM-09 ID: "); Serial.print(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bitCount(int x) {
|
|
||||||
int m4 = 0x1 | (0x1<<8) | (0x1<<16) | (0x1<<24);
|
|
||||||
int m1 = 0xFF;
|
|
||||||
int s4 = (x&m4) + ((x>>1)&m4) + ((x>>2)&m4) + ((x>>3)&m4) + ((x>>4)&m4) + ((x>>5)&m4) + ((x>>6)&m4) + ((x>>7)&m4);
|
|
||||||
int s1 = (s4&m1) + ((s4>>8)&m1) + ((s4>>16)&m1) + ((s4>>24)&m1);
|
|
||||||
return s1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t MON[]={0,0,31,59,90,120,151,181,212,243,273,304,334};
|
|
||||||
|
|
||||||
void DFM::decodeDAT(uint8_t *dat)
|
|
||||||
{
|
|
||||||
Serial.print(" DAT["); Serial.print(dat[6]); Serial.print("]: ");
|
|
||||||
switch(dat[6]) {
|
|
||||||
case 0:
|
|
||||||
Serial.print("Packet counter: "); Serial.print(dat[3]);
|
|
||||||
sonde.si()->frame = dat[3];
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
int val = (((uint16_t)dat[4])<<8) + (uint16_t)dat[5];
|
|
||||||
Serial.print("UTC-msec: "); Serial.print(val);
|
|
||||||
sonde.si()->sec = val/1000;
|
|
||||||
uint32_t tmp = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]);
|
|
||||||
sonde.si()->sats = bitCount(tmp); // maybe!?!?!?
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
float lat, vh;
|
|
||||||
lat = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]);
|
|
||||||
vh = ((uint16_t)dat[4]<<8) + dat[5];
|
|
||||||
Serial.print("GPS-lat: "); Serial.print(lat*0.0000001);
|
|
||||||
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;
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
float lon, dir;
|
|
||||||
lon = ((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);
|
|
||||||
sonde.si()->lon = lon*0.0000001;
|
|
||||||
sonde.si()->dir = dir*0.01;
|
|
||||||
sonde.si()->validPos |= 0x42;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
float alt, vv;
|
|
||||||
alt = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + dat[3];
|
|
||||||
vv = (int16_t)( ((int16_t)dat[4]<<8) | dat[5] );
|
|
||||||
Serial.print("GPS-height: "); Serial.print(alt*0.01);
|
|
||||||
Serial.print(", vv: "); Serial.print(vv*0.01);
|
|
||||||
sonde.si()->alt = alt*0.01;
|
|
||||||
sonde.si()->vs = vv*0.01;
|
|
||||||
sonde.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;
|
|
||||||
sonde.si()->time = tt;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Serial.print("(?)");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DFM::bitsToBytes(uint8_t *bits, uint8_t *bytes, int len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for(i=0; i<len*4; i++) {
|
|
||||||
//Serial.print(bits[i]?"1":"0");
|
|
||||||
bytes[i/8] = (bytes[i/8]<<1) | (bits[i]?1:0);
|
|
||||||
}
|
|
||||||
bytes[(i-1)/8] &= 0x0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DFM::receive() {
|
|
||||||
byte data[1000]; // pending data from previous mode may write more than 33 bytes. TODO.
|
|
||||||
for(int i=0; i<2; i++) {
|
|
||||||
sx1278.setPayloadLength(33); // Expect 33 bytes (7+13+13 bytes)
|
|
||||||
|
|
||||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
|
||||||
int e = sx1278.receivePacketTimeout(1000, data);
|
|
||||||
if(e) { return RX_TIMEOUT; } //if timeout... return 1
|
|
||||||
|
|
||||||
Serial.printf("inverse is %d\b", inverse);
|
|
||||||
if(!inverse) { for(int i=0; i<33; i++) { data[i]^=0xFF; } }
|
|
||||||
deinterleave(data, 7, hamming_conf);
|
|
||||||
deinterleave(data+7, 13, hamming_dat1);
|
|
||||||
deinterleave(data+20, 13, hamming_dat2);
|
|
||||||
|
|
||||||
int ret0 = hamming(hamming_conf, 7, block_conf);
|
|
||||||
int ret1 = hamming(hamming_dat1, 13, block_dat1);
|
|
||||||
int ret2 = hamming(hamming_dat2, 13, block_dat2);
|
|
||||||
|
|
||||||
byte byte_conf[4], byte_dat1[7], byte_dat2[7];
|
|
||||||
bitsToBytes(block_conf, byte_conf, 7);
|
|
||||||
bitsToBytes(block_dat1, byte_dat1, 13);
|
|
||||||
bitsToBytes(block_dat2, byte_dat2, 13);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
return RX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// moved to a single function in Sonde(). This function can be used for additional
|
|
||||||
// processing here, that takes too long for doing in the RX task loop
|
|
||||||
int DFM::waitRXcomplete() {
|
|
||||||
#if 0
|
|
||||||
int res=0;
|
|
||||||
uint32_t t0 = millis();
|
|
||||||
while( rxtask.receiveResult < 0 && millis()-t0 < 2000) { delay(50); }
|
|
||||||
|
|
||||||
if( rxtask.receiveResult<0 || rxtask.receiveResult==RX_TIMEOUT) {
|
|
||||||
res = RX_TIMEOUT;
|
|
||||||
} else if ( rxtask.receiveResult ==0) {
|
|
||||||
res = RX_OK;
|
|
||||||
} else {
|
|
||||||
res = RX_ERROR;
|
|
||||||
}
|
|
||||||
rxtask.receiveResult = -1;
|
|
||||||
Serial.printf("waitRXcomplete returning %d\n", res);
|
|
||||||
return res;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFM dfm = DFM();
|
|
||||||
@@ -194,7 +194,7 @@ uint8_t SX1278FSK::setFSK()
|
|||||||
{
|
{
|
||||||
uint8_t state = 2;
|
uint8_t state = 2;
|
||||||
byte st0;
|
byte st0;
|
||||||
byte config1;
|
//byte config1;
|
||||||
|
|
||||||
#if (SX1278FSK_debug_mode > 1)
|
#if (SX1278FSK_debug_mode > 1)
|
||||||
Serial.println();
|
Serial.println();
|
||||||
Executable
+657
@@ -0,0 +1,657 @@
|
|||||||
|
/* DFM decoder functions */
|
||||||
|
#include "DFM.h"
|
||||||
|
#include "SX1278FSK.h"
|
||||||
|
#include "Sonde.h"
|
||||||
|
|
||||||
|
#define DFM_DEBUG 1
|
||||||
|
|
||||||
|
#if DFM_DEBUG
|
||||||
|
#define DFM_DBG(x) x
|
||||||
|
#else
|
||||||
|
#define DFM_DBG(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DFM_FRAMELEN 33
|
||||||
|
|
||||||
|
// single data structure, search restarts after decoder change
|
||||||
|
static struct st_dfmstat {
|
||||||
|
int idcnt0;
|
||||||
|
int idcnt1;
|
||||||
|
int lastfrid;
|
||||||
|
int lastfrcnt;
|
||||||
|
uint8_t start[50];
|
||||||
|
uint16_t dat[50*2];
|
||||||
|
uint8_t cnt[50*2];
|
||||||
|
uint8_t nameregok;
|
||||||
|
uint8_t nameregtop;
|
||||||
|
} dfmstate;
|
||||||
|
|
||||||
|
int DFM::setup(float frequency, int type)
|
||||||
|
{
|
||||||
|
stype = type;
|
||||||
|
#if DFM_DEBUG
|
||||||
|
Serial.printf("Setup sx1278 for DFM sonde (type=%d)\n", stype);
|
||||||
|
#endif
|
||||||
|
if(sx1278.ON()!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setFSK()!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting FSM mode FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setBitrate(2500)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting bitrate 2500bit/s FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#if DFM_DEBUG
|
||||||
|
float br = sx1278.getBitrate();
|
||||||
|
Serial.print("Exact bitrate is ");
|
||||||
|
Serial.println(br);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(sx1278.setAFCBandwidth(sonde.config.dfm.agcbw)!=0) {
|
||||||
|
DFM_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.dfm.agcbw));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setRxBandwidth(sonde.config.dfm.rxbw)!=0) {
|
||||||
|
DFM_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.dfm.rxbw));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == STYPE_DFM09 || type == STYPE_DFM06) {
|
||||||
|
// packet mode, old version, misses some frames because chip enables rx too late after
|
||||||
|
// one frame was recevied. TODO: check if this can be fixed by changing parameters
|
||||||
|
// Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
||||||
|
if(sx1278.setRxConf(0x1E)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting RX Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Set autostart_RX to 01, preamble 0, SYNC detect==on, syncsize=3 (==4 byte
|
||||||
|
//char header[] = "0110.0101 0110.0110 1010.0101 1010.1010";
|
||||||
|
|
||||||
|
const char *SYNC=(stype==STYPE_DFM09)?"\x9A\x99\x5A\x55":"\x65\x66\xA5\xAA";
|
||||||
|
if(sx1278.setSyncConf(0x53, 4, (const uint8_t *)SYNC)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting SYNC Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
//if(sx1278.setPreambleDetect(0xA8)!=0) {
|
||||||
|
if(sx1278.setPreambleDetect(0xAA)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packet config 1: fixed len, mancecer, no crc, no address filter
|
||||||
|
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
||||||
|
if(sx1278.setPacketConfig(0x28, 0x40)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting Packet config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sx1278.setPayloadLength(33); // Expect 33 bytes (7+13+13 bytes)
|
||||||
|
} else {
|
||||||
|
// continuous mode
|
||||||
|
// Enable auto-AFC, auto-AGC, RX Trigger by preamble ????
|
||||||
|
if(sx1278.setRxConf(0x1E)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting RX Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// working with continuous RX
|
||||||
|
const char *SYNC="\xAA\xAA";
|
||||||
|
if(sx1278.setSyncConf(0x70, 2, (const uint8_t *)SYNC)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting SYNC Config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setPreambleDetect(0xA8)!=0) {
|
||||||
|
//if(sx1278.setPreambleDetect(0x9F)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(sx1278.setPacketConfig(0x08, 0x40)!=0) {
|
||||||
|
DFM_DBG(Serial.println("Setting Packet config FAILED"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sx1278.setPayloadLength(0); // infinite for now...
|
||||||
|
}
|
||||||
|
Serial.print("DFM: setting RX frequency to ");
|
||||||
|
Serial.println(frequency);
|
||||||
|
|
||||||
|
int retval = sx1278.setFrequency(frequency);
|
||||||
|
sx1278.clearIRQFlags();
|
||||||
|
|
||||||
|
// Do this only once in setup in continous mode
|
||||||
|
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||||
|
|
||||||
|
memset((void *)&dfmstate, 0, sizeof(dfmstate));
|
||||||
|
DFM_DBG(Serial.println("Setting SX1278 config for DFM finished\n"); Serial.println());
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define bitpick(value,bitpos) (((value)>>(7-(bitpos)))&0x01)
|
||||||
|
// Input: str: packed data, MSB first
|
||||||
|
void DFM::deinterleave(uint8_t *str, int L, uint8_t *block) {
|
||||||
|
int i, j;
|
||||||
|
for (j = 0; j < B; j++) { // L = 7 (CFG), 13 (DAT1, DAT2)
|
||||||
|
for (i = 0; i < L; i++) {
|
||||||
|
block[B*i+j] = bitpick( str[(L*j+i)/8], (L*j+i)&7 )?0:1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DFM::bits2val(const uint8_t *bits, int len) {
|
||||||
|
uint32_t val = 0;
|
||||||
|
for (int j = 0; j < len; j++) {
|
||||||
|
val |= (bits[j] << (len-1-j));
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error correction for hamming code
|
||||||
|
// returns 0: ok >0: 1 error was corrected -1: uncorrectable error
|
||||||
|
int DFM::check(uint8_t code[8]) {
|
||||||
|
int i, j;
|
||||||
|
uint32_t synval = 0;
|
||||||
|
uint8_t syndrom[4];
|
||||||
|
int ret=0;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
syndrom[i] = 0;
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
syndrom[i] ^= H[i][j] & code[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
synval = bits2val(syndrom, 4);
|
||||||
|
if (synval) {
|
||||||
|
ret = -1;
|
||||||
|
for (j = 0; j < 8; j++) { // 1-bit-error
|
||||||
|
if (synval == He[j]) { // reicht auf databits zu pruefen, d.h.
|
||||||
|
ret = j+1; // (systematischer Code) He[0..3]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else ret = 0;
|
||||||
|
if (ret > 0) code[ret-1] ^= 0x1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extended (8,4) Hamming code
|
||||||
|
// Return number of corrected bits, -1 if uncorrectable error
|
||||||
|
int DFM::hamming(uint8_t *ham, int L, uint8_t *sym) {
|
||||||
|
int i, j;
|
||||||
|
int ret = 0; // DFM: length L = 7 or 13
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
// systematic Hamming code: copy bits 0..3
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
sym[4*i+j] = ham[8*i+j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DFM::DFM() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFM::printRaw(const char *label, int len, int ret, const uint8_t *data)
|
||||||
|
{
|
||||||
|
Serial.print(label); Serial.print("(");
|
||||||
|
Serial.print(ret);
|
||||||
|
Serial.print("):");
|
||||||
|
int i;
|
||||||
|
for(i=0; i<len/2; i++) {
|
||||||
|
char str[10];
|
||||||
|
snprintf(str, 10, "%02X", data[i]);
|
||||||
|
Serial.print(str);
|
||||||
|
}
|
||||||
|
Serial.print(data[i]&0x0F, HEX);
|
||||||
|
Serial.print(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* typestr[16]={
|
||||||
|
"", "", "", "", "", "", // 00..05
|
||||||
|
"DFM6", // 06 => DFM6
|
||||||
|
"PS15", // 07 => PS15 (untested)
|
||||||
|
"", "",
|
||||||
|
"DFM9", // 0A => DFM9
|
||||||
|
"DF17", // 0B => DFM17?
|
||||||
|
"DF9P", // 0C => DFM9P or DFM17 test
|
||||||
|
"DF17", // 0D => DFM17
|
||||||
|
"", ""
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DFMIDTHRESHOLD 2
|
||||||
|
/* inspired by oe5dxl's finddnmae in sondeudp.c of dxlaprs */
|
||||||
|
void DFM::finddfname(uint8_t *b)
|
||||||
|
{
|
||||||
|
uint8_t st;
|
||||||
|
uint32_t thres;
|
||||||
|
uint32_t i;
|
||||||
|
uint8_t ix;
|
||||||
|
uint16_t d;
|
||||||
|
|
||||||
|
st = b[0]; /* frame start byte */
|
||||||
|
ix = b[3]; /* hi/lo part of ser; (LSB due to our bitsToBytes...) */
|
||||||
|
d = (b[1]<<8) + b[2]; /* data byte */
|
||||||
|
/* find highest channel number single frame serial,
|
||||||
|
(2 frame serial will make a single serial too) */
|
||||||
|
if(dfmstate.idcnt0 < DFMIDTHRESHOLD && dfmstate.idcnt1 < DFMIDTHRESHOLD) {
|
||||||
|
uint32_t v = (st<<20) | (d<<4) | ix;
|
||||||
|
if ( st > (dfmstate.lastfrid>>20) ) {
|
||||||
|
dfmstate.lastfrid = v;
|
||||||
|
Serial.print(" MAXCH:"); Serial.print(st);
|
||||||
|
dfmstate.lastfrcnt = 0;
|
||||||
|
} else if ( st == (dfmstate.lastfrid>>20) ) {
|
||||||
|
/* same id found */
|
||||||
|
if (v == dfmstate.lastfrid) {
|
||||||
|
++dfmstate.lastfrcnt;
|
||||||
|
thres = DFMIDTHRESHOLD * 2;
|
||||||
|
/* may be a 2 frame serial so increase safety level */
|
||||||
|
if (ix <= 1) thres *= 2;
|
||||||
|
/* may be not a dfm6 so increase safety level */
|
||||||
|
if ( (st>>4) != 6) thres *= 2;
|
||||||
|
if (dfmstate.lastfrcnt >= thres) {
|
||||||
|
/* id found */
|
||||||
|
if (dfmstate.lastfrcnt == thres) {
|
||||||
|
uint32_t id = ((st&0x0F)<<20) | (d<<4) | ix;
|
||||||
|
uint32_t chkid = id;
|
||||||
|
int i;
|
||||||
|
/* check validity */
|
||||||
|
for(i=0; i<6; i++) {
|
||||||
|
if((chkid&0x0f)>9) { break; /* not ok */ }
|
||||||
|
chkid >>= 4;
|
||||||
|
}
|
||||||
|
if(i==6) {
|
||||||
|
snprintf(sonde.si()->id, 10, "D%x ", id);
|
||||||
|
sonde.si()->validID = true;
|
||||||
|
strncpy(sonde.si()->typestr, typestr[ (st>>4)&0x0F ], 5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dfmstate.lastfrcnt = 0;
|
||||||
|
Serial.print(" NOT NUMERIC SERIAL");
|
||||||
|
}
|
||||||
|
//anonym->idtime = osic_time();
|
||||||
|
} else {
|
||||||
|
Serial.print(" MAXCHCNT/SECLVL:");
|
||||||
|
Serial.print(dfmstate.lastfrcnt);
|
||||||
|
Serial.print("/");
|
||||||
|
Serial.print(thres);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dfmstate.lastfrid = v; /* not stable ser */
|
||||||
|
dfmstate.lastfrcnt = 0UL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /*find highest channel number single frame serial */
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i<dfmstate.nameregtop && dfmstate.start[i]!=st) i++;
|
||||||
|
Serial.printf(" %02x:i=%d,top=%d", st, i, dfmstate.nameregtop);
|
||||||
|
if (i<dfmstate.nameregtop) {
|
||||||
|
if (ix<=1UL && (dfmstate.cnt[2*i+ix]==0 || dfmstate.dat[2*i+ix]==d)) {
|
||||||
|
dfmstate.dat[2*i+ix] = d;
|
||||||
|
if(dfmstate.cnt[2*i+ix] < 255) dfmstate.cnt[2*i+ix]++;
|
||||||
|
Serial.print(" ID:");
|
||||||
|
Serial.print(st, HEX);
|
||||||
|
Serial.print("[");
|
||||||
|
Serial.print(ix);
|
||||||
|
Serial.print("] CNT:");
|
||||||
|
Serial.print(dfmstate.cnt[2*i]);
|
||||||
|
Serial.print(",");
|
||||||
|
Serial.print(dfmstate.cnt[2*i+1]);
|
||||||
|
Serial.print(",st=");
|
||||||
|
Serial.print(st);
|
||||||
|
Serial.print(",lastfrid=");
|
||||||
|
Serial.print(dfmstate.lastfrid>>20);
|
||||||
|
if( (dfmstate.cnt[2*i]>DFMIDTHRESHOLD && dfmstate.cnt[2*i+1]>DFMIDTHRESHOLD) ||
|
||||||
|
(dfmstate.cnt[2*i]>0 && dfmstate.cnt[2*i+1]>0 && st == (dfmstate.lastfrid>>20) && (st>>4)>6) ) {
|
||||||
|
if(dfmstate.idcnt0 <= 1) {
|
||||||
|
dfmstate.idcnt0 = dfmstate.cnt[2*i];
|
||||||
|
dfmstate.idcnt1 = dfmstate.cnt[2*i+1];
|
||||||
|
dfmstate.nameregok = i;
|
||||||
|
// generate id.....
|
||||||
|
snprintf(sonde.si()->id, 10, "D%d", ((dfmstate.dat[2*i]<<16)|dfmstate.dat[2*i+1])%100000000);
|
||||||
|
Serial.print("\nNEW AUTOID:");
|
||||||
|
Serial.println(sonde.si()->id);
|
||||||
|
sonde.si()->validID = true;
|
||||||
|
strncpy(sonde.si()->typestr, typestr[ (st>>4)&0x0F ], 5);
|
||||||
|
}
|
||||||
|
if(dfmstate.nameregok==i) {
|
||||||
|
Serial.print(" ID OK");
|
||||||
|
// idtime = .... /* TODO */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* data changed so not ser */
|
||||||
|
dfmstate.cnt[2*i] = 0;
|
||||||
|
dfmstate.cnt[2*i+1] = 0;
|
||||||
|
if(dfmstate.nameregok == i) { /* found id wrong */
|
||||||
|
dfmstate.idcnt0 = 0;
|
||||||
|
dfmstate.idcnt1 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ix<=1) { /* add new entry for possible ID */
|
||||||
|
dfmstate.start[dfmstate.nameregtop] = st;
|
||||||
|
dfmstate.cnt[2*dfmstate.nameregtop] = 0;
|
||||||
|
dfmstate.cnt[2*dfmstate.nameregtop+1] = 0;
|
||||||
|
dfmstate.cnt[2*dfmstate.nameregtop+ix] = 1;
|
||||||
|
dfmstate.dat[2*dfmstate.nameregtop+ix] = d;
|
||||||
|
if(dfmstate.nameregtop<49) dfmstate.nameregtop++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFM::decodeCFG(uint8_t *cfg)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// new ID
|
||||||
|
finddfname(cfg);
|
||||||
|
// new aprs ID (dxlaprs, autorx) is now "D" + serial (8 digits) by consensus
|
||||||
|
memcpy(sonde.si()->ser, sonde.si()->id+1, 9);
|
||||||
|
#else
|
||||||
|
// old ID
|
||||||
|
static int lowid, highid, idgood=0, type=0;
|
||||||
|
if((cfg[0]>>4)==0x06 && type==0) { // DFM-6 ID
|
||||||
|
lowid = ((cfg[0]&0x0F)<<20) | (cfg[1]<<12) | (cfg[2]<<4) | (cfg[3]&0x0f);
|
||||||
|
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
|
||||||
|
type=9;
|
||||||
|
if(cfg[3]==1) {
|
||||||
|
lowid = (cfg[1]<<8) | cfg[2];
|
||||||
|
idgood |= 1;
|
||||||
|
} else {
|
||||||
|
highid = (cfg[1]<<8) | cfg[2];
|
||||||
|
idgood |= 2;
|
||||||
|
}
|
||||||
|
if(idgood==3) {
|
||||||
|
uint32_t dfmid = (highid<<16) | lowid;
|
||||||
|
Serial.print("DFM-09 ID: "); Serial.print(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bitCount(int x) {
|
||||||
|
int m4 = 0x1 | (0x1<<8) | (0x1<<16) | (0x1<<24);
|
||||||
|
int m1 = 0xFF;
|
||||||
|
int s4 = (x&m4) + ((x>>1)&m4) + ((x>>2)&m4) + ((x>>3)&m4) + ((x>>4)&m4) + ((x>>5)&m4) + ((x>>6)&m4) + ((x>>7)&m4);
|
||||||
|
int s1 = (s4&m1) + ((s4>>8)&m1) + ((s4>>16)&m1) + ((s4>>24)&m1);
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t MON[]={0,0,31,59,90,120,151,181,212,243,273,304,334};
|
||||||
|
|
||||||
|
void DFM::decodeDAT(uint8_t *dat)
|
||||||
|
{
|
||||||
|
Serial.print(" DAT["); Serial.print(dat[6]); Serial.print("]: ");
|
||||||
|
switch(dat[6]) {
|
||||||
|
case 0:
|
||||||
|
Serial.print("Packet counter: "); Serial.print(dat[3]);
|
||||||
|
sonde.si()->frame = dat[3];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int val = (((uint16_t)dat[4])<<8) + (uint16_t)dat[5];
|
||||||
|
Serial.print("UTC-msec: "); Serial.print(val);
|
||||||
|
sonde.si()->sec = val/1000;
|
||||||
|
uint32_t tmp = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]);
|
||||||
|
sonde.si()->sats = bitCount(tmp); // maybe!?!?!?
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
float lat, vh;
|
||||||
|
lat = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + ((uint32_t)dat[3]);
|
||||||
|
vh = ((uint16_t)dat[4]<<8) + dat[5];
|
||||||
|
Serial.print("GPS-lat: "); Serial.print(lat*0.0000001);
|
||||||
|
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;
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
float lon, dir;
|
||||||
|
lon = ((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);
|
||||||
|
sonde.si()->lon = lon*0.0000001;
|
||||||
|
sonde.si()->dir = dir*0.01;
|
||||||
|
sonde.si()->validPos |= 0x42;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
float alt, vv;
|
||||||
|
alt = ((uint32_t)dat[0]<<24) + ((uint32_t)dat[1]<<16) + ((uint32_t)dat[2]<<8) + dat[3];
|
||||||
|
vv = (int16_t)( ((int16_t)dat[4]<<8) | dat[5] );
|
||||||
|
Serial.print("GPS-height: "); Serial.print(alt*0.01);
|
||||||
|
Serial.print(", vv: "); Serial.print(vv*0.01);
|
||||||
|
sonde.si()->alt = alt*0.01;
|
||||||
|
sonde.si()->vs = vv*0.01;
|
||||||
|
sonde.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;
|
||||||
|
sonde.si()->time = tt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.print("(?)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DFM::bitsToBytes(uint8_t *bits, uint8_t *bytes, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<len*4; i++) {
|
||||||
|
//Serial.print(bits[i]?"1":"0");
|
||||||
|
bytes[i/8] = (bytes[i/8]<<1) | (bits[i]?1:0);
|
||||||
|
}
|
||||||
|
bytes[(i-1)/8] &= 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int haveNewFrame = 0;
|
||||||
|
|
||||||
|
int DFM::processDFMdata(uint8_t dt) {
|
||||||
|
static uint8_t data[1024];
|
||||||
|
static uint32_t rxdata = 0;
|
||||||
|
static uint8_t rxbitc = 0;
|
||||||
|
static uint8_t rxbyte = 0;
|
||||||
|
static uint8_t rxsearching = 1;
|
||||||
|
static uint8_t rxp;
|
||||||
|
static int rssi=0, fei=0, afc=0;
|
||||||
|
static uint8_t invers = 0;
|
||||||
|
|
||||||
|
for(int i=0; i<8; i++) {
|
||||||
|
uint8_t d = (dt&0x80)?1:0;
|
||||||
|
dt <<= 1;
|
||||||
|
rxdata = (rxdata<<1) | d;
|
||||||
|
if( (rxbitc&1)==0 ) {
|
||||||
|
// "bit1"
|
||||||
|
rxbyte = (rxbyte<<1) | d;
|
||||||
|
} else {
|
||||||
|
// "bit2" ==> 01 or 10 => 1, otherweise => 0
|
||||||
|
// not here: (10=>1, 01=>0)!!! rxbyte = rxbyte ^ d;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if(rxsearching) {
|
||||||
|
if( rxdata == 0x6566A5AA || rxdata == 0x9A995A55 ) {
|
||||||
|
rxsearching = false;
|
||||||
|
rxbitc = 0;
|
||||||
|
rxp = 0;
|
||||||
|
rxbyte = 0;
|
||||||
|
rssi=sx1278.getRSSI();
|
||||||
|
fei=sx1278.getFEI();
|
||||||
|
afc=sx1278.getAFC();
|
||||||
|
sonde.si()->rssi = rssi;
|
||||||
|
sonde.si()->afc = afc;
|
||||||
|
invers = (rxdata == 0x6566A5AA)?1:0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rxbitc = (rxbitc+1)%16; // 16;
|
||||||
|
if(rxbitc == 0) { // got 8 data bit
|
||||||
|
if(invers) rxbyte=~rxbyte;
|
||||||
|
data[rxp++] = rxbyte&0xff; // (rxbyte>>1)&0xff;
|
||||||
|
if(rxp>=DFM_FRAMELEN) {
|
||||||
|
rxsearching = true;
|
||||||
|
//Serial.println("Got a DFM frame!");
|
||||||
|
Serial.print("[RSSI="); Serial.print(rssi);
|
||||||
|
Serial.print(" FEI="); Serial.print(fei);
|
||||||
|
Serial.print(" AFC="); Serial.print(afc); Serial.print("] ");
|
||||||
|
decodeFrameDFM(data);
|
||||||
|
haveNewFrame = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DFM::receive() {
|
||||||
|
if( stype == STYPE_DFM ) {
|
||||||
|
return receiveNew();
|
||||||
|
} else {
|
||||||
|
return receiveOld();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DFM::receiveNew() {
|
||||||
|
int rxframes = 4;
|
||||||
|
// tentative continuous RX version...
|
||||||
|
unsigned long t0 = millis();
|
||||||
|
while( ( millis() - t0 ) < 1000 ) {
|
||||||
|
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
|
if ( bitRead(value, 7) ) {
|
||||||
|
Serial.println("FIFO full");
|
||||||
|
}
|
||||||
|
if ( bitRead(value, 4) ) {
|
||||||
|
Serial.println("FIFO overflow");
|
||||||
|
// new: (maybe clear only overflow??) TODO
|
||||||
|
sx1278.clearIRQFlags();
|
||||||
|
}
|
||||||
|
if ( bitRead(value, 2) == 1 ) {
|
||||||
|
Serial.println("FIFO: payload ready()");
|
||||||
|
// does not make much sence? (from m10): TODO
|
||||||
|
// ??????? sx1278.clearIRQFlags();
|
||||||
|
}
|
||||||
|
if(bitRead(value, 6) == 0) { // while FIFO not empty
|
||||||
|
byte data = sx1278.readRegister(REG_FIFO);
|
||||||
|
processDFMdata(data);
|
||||||
|
value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
|
} else {
|
||||||
|
#if 0
|
||||||
|
if(headerDetected) {
|
||||||
|
t0 = millis(); // restart timer... don't time out if header detected...
|
||||||
|
headerDetected = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(haveNewFrame) {
|
||||||
|
//Serial.printf("DFM::receive(): new frame complete after %ldms\n", millis()-t0);
|
||||||
|
haveNewFrame = 0;
|
||||||
|
rxframes--;
|
||||||
|
if(rxframes==0) return RX_OK;
|
||||||
|
}
|
||||||
|
delay(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RX_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DFM::receiveOld() {
|
||||||
|
byte data[1000]; // pending data from previous mode may write more than 33 bytes. TODO.
|
||||||
|
for(int i=0; i<2; i++) {
|
||||||
|
sx1278.setPayloadLength(33); // Expect 33 bytes (7+13+13 bytes)
|
||||||
|
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||||
|
//int t = millis();
|
||||||
|
int e = sx1278.receivePacketTimeout(1000, data);
|
||||||
|
//Serial.printf("rxPTO done after %d ms", (int)(millis()-t));
|
||||||
|
if(e) { return RX_TIMEOUT; } //if timeout... return 1
|
||||||
|
|
||||||
|
if(!(stype==STYPE_DFM09)) { for(int i=0; i<33; i++) { data[i]^=0xFF; } }
|
||||||
|
decodeFrameDFM(data);
|
||||||
|
}
|
||||||
|
return RX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DFM::decodeFrameDFM(uint8_t *data) {
|
||||||
|
deinterleave(data, 7, hamming_conf);
|
||||||
|
deinterleave(data+7, 13, hamming_dat1);
|
||||||
|
deinterleave(data+20, 13, hamming_dat2);
|
||||||
|
#if 0
|
||||||
|
Serial.print("RAWCFG:");
|
||||||
|
for(int i=0; i<7*8; i++) {
|
||||||
|
Serial.print(hamming_conf[i]?"1":"0");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ret0 = hamming(hamming_conf, 7, block_conf);
|
||||||
|
int ret1 = hamming(hamming_dat1, 13, block_dat1);
|
||||||
|
int ret2 = hamming(hamming_dat2, 13, block_dat2);
|
||||||
|
|
||||||
|
byte byte_conf[4], byte_dat1[7], byte_dat2[7];
|
||||||
|
bitsToBytes(block_conf, byte_conf, 7);
|
||||||
|
bitsToBytes(block_dat1, byte_dat1, 13);
|
||||||
|
bitsToBytes(block_dat2, byte_dat2, 13);
|
||||||
|
|
||||||
|
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);
|
||||||
|
Serial.println("");
|
||||||
|
return RX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// moved to a single function in Sonde(). This function can be used for additional
|
||||||
|
// processing here, that takes too long for doing in the RX task loop
|
||||||
|
int DFM::waitRXcomplete() {
|
||||||
|
#if 0
|
||||||
|
int res=0;
|
||||||
|
uint32_t t0 = millis();
|
||||||
|
while( rxtask.receiveResult < 0 && millis()-t0 < 2000) { delay(50); }
|
||||||
|
|
||||||
|
if( rxtask.receiveResult<0 || rxtask.receiveResult==RX_TIMEOUT) {
|
||||||
|
res = RX_TIMEOUT;
|
||||||
|
} else if ( rxtask.receiveResult ==0) {
|
||||||
|
res = RX_OK;
|
||||||
|
} else {
|
||||||
|
res = RX_ERROR;
|
||||||
|
}
|
||||||
|
rxtask.receiveResult = -1;
|
||||||
|
Serial.printf("waitRXcomplete returning %d\n", res);
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DFM dfm = DFM();
|
||||||
|
|
||||||
@@ -23,16 +23,23 @@
|
|||||||
class DFM
|
class DFM
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int inverse=0;
|
int stype;
|
||||||
|
char *stypename=NULL;
|
||||||
|
|
||||||
void deinterleave(uint8_t *str, int L, uint8_t *block);
|
void deinterleave(uint8_t *str, int L, uint8_t *block);
|
||||||
uint32_t bits2val(const uint8_t *bits, int len);
|
uint32_t bits2val(const uint8_t *bits, int len);
|
||||||
int check(uint8_t code[8]);
|
int check(uint8_t code[8]);
|
||||||
int hamming(uint8_t *ham, int L, uint8_t *sym);
|
int hamming(uint8_t *ham, int L, uint8_t *sym);
|
||||||
void printRaw(const char *prefix, int len, int ret, const uint8_t* data);
|
void printRaw(const char *prefix, int len, int ret, const uint8_t* data);
|
||||||
|
void finddfname(uint8_t *cfg);
|
||||||
void decodeCFG(uint8_t *cfg);
|
void decodeCFG(uint8_t *cfg);
|
||||||
void decodeDAT(uint8_t *dat);
|
void decodeDAT(uint8_t *dat);
|
||||||
void bitsToBytes(uint8_t *bits, uint8_t *bytes, int len);
|
void bitsToBytes(uint8_t *bits, uint8_t *bytes, int len);
|
||||||
|
int processDFMdata(uint8_t dt);
|
||||||
|
int decodeFrameDFM(uint8_t *data);
|
||||||
|
int receiveOld();
|
||||||
|
int receiveNew();
|
||||||
|
|
||||||
|
|
||||||
#define B 8
|
#define B 8
|
||||||
#define S 4
|
#define S 4
|
||||||
@@ -55,7 +62,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
DFM();
|
DFM();
|
||||||
// main decoder API
|
// main decoder API
|
||||||
int setup(float frequency, int inverse);
|
int setup(float frequency, int type);
|
||||||
int receive();
|
int receive();
|
||||||
int waitRXcomplete();
|
int waitRXcomplete();
|
||||||
|
|
||||||
@@ -13,11 +13,11 @@ int readLine(Stream &stream, char *buffer, int maxlen);
|
|||||||
extern const char *version_name;
|
extern const char *version_name;
|
||||||
extern const char *version_id;
|
extern const char *version_id;
|
||||||
|
|
||||||
#include <../fonts/FreeMono9pt7b.h>
|
#include <fonts/FreeMono9pt7b.h>
|
||||||
#include <../fonts/FreeMono12pt7b.h>
|
#include <fonts/FreeMono12pt7b.h>
|
||||||
#include <../fonts/FreeSans9pt7b.h>
|
#include <fonts/FreeSans9pt7b.h>
|
||||||
#include <../fonts/FreeSans12pt7b.h>
|
#include <fonts/FreeSans12pt7b.h>
|
||||||
#include <../fonts/Picopixel.h>
|
#include <fonts/Picopixel.h>
|
||||||
|
|
||||||
extern Sonde sonde;
|
extern Sonde sonde;
|
||||||
|
|
||||||
@@ -30,7 +30,8 @@ extern SemaphoreHandle_t axpSemaphore;
|
|||||||
|
|
||||||
SPIClass spiDisp(HSPI);
|
SPIClass spiDisp(HSPI);
|
||||||
|
|
||||||
const char *sondeTypeStr[NSondeTypes] = { "DFM6", "DFM9", "RS41", "RS92", "M10 ", "M20 " };
|
const char *sondeTypeStr[NSondeTypes] = { "DFM6", "DFM9", "RS41", "RS92", "M10 ", "M20 ", "DFM " };
|
||||||
|
const char sondeTypeChar[NSondeTypes] = { '6', '9', '4', 'R', 'M', '2', 'D' };
|
||||||
|
|
||||||
byte myIP_tiles[8*11];
|
byte myIP_tiles[8*11];
|
||||||
static uint8_t ap_tile[8]={0x00,0x04,0x22,0x92, 0x92, 0x22, 0x04, 0x00};
|
static uint8_t ap_tile[8]={0x00,0x04,0x22,0x92, 0x92, 0x22, 0x04, 0x00};
|
||||||
@@ -268,12 +269,12 @@ void U8x8Display::drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y
|
|||||||
void U8x8Display::welcome() {
|
void U8x8Display::welcome() {
|
||||||
u8x8->clear();
|
u8x8->clear();
|
||||||
setFont(FONT_LARGE);
|
setFont(FONT_LARGE);
|
||||||
drawString(8 - strlen(version_name) / 2, 1, version_name);
|
drawString(0, 1, version_name);
|
||||||
//drawString(8 - strlen(version_id) / 2, 2, version_id);
|
drawString(11, 1, version_id);
|
||||||
setFont(FONT_SMALL);
|
setFont(FONT_SMALL);
|
||||||
drawString(0, 4, "RS41/92,DFM,M1&2");
|
drawString(0, 4, "RS41/92,DFM,M1&2");
|
||||||
drawString(0, 6, "by FRS2013 ");
|
drawString(0, 6, "by Vigor & Xav ");
|
||||||
drawString(11, 6, version_id);
|
//drawString(11, 6, version_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static String previp;
|
static String previp;
|
||||||
@@ -858,7 +859,7 @@ void Display::drawHS(DispEntry *de) {
|
|||||||
}
|
}
|
||||||
boolean is_ms = (de->extra && de->extra[0]=='m')?true:false; // m/s or km/h
|
boolean is_ms = (de->extra && de->extra[0]=='m')?true:false; // m/s or km/h
|
||||||
float hs = sonde.si()->hs;
|
float hs = sonde.si()->hs;
|
||||||
if(is_ms) hs = hs / 3.6;
|
if(is_ms) hs = hs * 3.6;
|
||||||
boolean has_extra = (de->extra && de->extra[1]!=0)? true: false;
|
boolean has_extra = (de->extra && de->extra[1]!=0)? true: false;
|
||||||
snprintf(buf, 16, hs>99?" %3.0f":" %2.1f", hs);
|
snprintf(buf, 16, hs>99?" %3.0f":" %2.1f", hs);
|
||||||
if(has_extra) { strcat(buf, de->extra+1); }
|
if(has_extra) { strcat(buf, de->extra+1); }
|
||||||
@@ -1214,7 +1215,7 @@ void Display::calcDurVol() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
heure=99;
|
heure=0;
|
||||||
}
|
}
|
||||||
sonde.si()->durvolheure=heure;
|
sonde.si()->durvolheure=heure;
|
||||||
sonde.si()->durvolminute=minute;
|
sonde.si()->durvolminute=minute;
|
||||||
@@ -80,12 +80,13 @@ int M10::setup(float frequency)
|
|||||||
//const char *SYNC="\x99\x9A";
|
//const char *SYNC="\x99\x9A";
|
||||||
#if 1
|
#if 1
|
||||||
// version 1, working with continuous RX
|
// version 1, working with continuous RX
|
||||||
const char *SYNC="\x66\x65";
|
//const char *SYNC="\x66\x65";
|
||||||
if(sx1278.setSyncConf(0x70, 2, (const uint8_t *)SYNC)!=0) {
|
|
||||||
|
const char *SYNC="\x99\x99\x4C\x99";
|
||||||
|
if(sx1278.setSyncConf(0x70, 4, (const uint8_t *)SYNC)!=0) {
|
||||||
M10_DBG(Serial.println("Setting SYNC Config FAILED"));
|
M10_DBG(Serial.println("Setting SYNC Config FAILED"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
//if(sx1278.setPreambleDetect(0xA8)!=0) {
|
|
||||||
if((sx1278.setPreambleDetect(0x9F)!=0)&&((sx1278.setPreambleDetect(0xAF)!=0))) {
|
if((sx1278.setPreambleDetect(0x9F)!=0)&&((sx1278.setPreambleDetect(0xAF)!=0))) {
|
||||||
M10_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
M10_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
||||||
return 1;
|
return 1;
|
||||||
@@ -258,7 +259,7 @@ int M10::decodeframeM10(uint8_t *data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Serial.println(crcok?"CRC OK":"CRC NOT OK");
|
Serial.println(crcok?"CRC OK":"CRC NOT OK");
|
||||||
//M10 0x9F M10Plus 0xAF M20 0x20
|
//M10 0x9F M10Plus 0xAF
|
||||||
if((data[1]==0x9F && data[2]==0x20) || (data[1]==0xAF && data[2]==0x20)) {
|
if((data[1]==0x9F && data[2]==0x20) || (data[1]==0xAF && data[2]==0x20)) {
|
||||||
Serial.println("Decoding...");
|
Serial.println("Decoding...");
|
||||||
// Its a M10
|
// Its a M10
|
||||||
@@ -381,7 +382,7 @@ void M10::processM10data(uint8_t dt)
|
|||||||
int M10::receive() {
|
int M10::receive() {
|
||||||
unsigned long t0 = millis();
|
unsigned long t0 = millis();
|
||||||
Serial.printf("M10::receive() start at %ld\n",t0);
|
Serial.printf("M10::receive() start at %ld\n",t0);
|
||||||
while( millis() - t0 < 1000 ) {
|
while( millis() - t0 < 1512 ) {
|
||||||
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
if ( bitRead(value, 7) ) {
|
if ( bitRead(value, 7) ) {
|
||||||
Serial.println("FIFO full");
|
Serial.println("FIFO full");
|
||||||
@@ -79,8 +79,9 @@ int M20::setup(float frequency)
|
|||||||
//const char *SYNC="\x99\x9A";
|
//const char *SYNC="\x99\x9A";
|
||||||
#if 1
|
#if 1
|
||||||
// version 1, working with continuous RX
|
// version 1, working with continuous RX
|
||||||
const char *SYNC="\x66\x65";
|
//const char *SYNC="\x66\x65";
|
||||||
if(sx1278.setSyncConf(0x70, 2, (const uint8_t *)SYNC)!=0) {
|
const char *SYNC="\x99\x99\x4C\x99";
|
||||||
|
if(sx1278.setSyncConf(0x70, 4, (const uint8_t *)SYNC)!=0) {
|
||||||
M20_DBG(Serial.println("Setting SYNC Config FAILED"));
|
M20_DBG(Serial.println("Setting SYNC Config FAILED"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -159,7 +160,7 @@ M20::M20() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define M20_FRAMELEN 70
|
#define M20_FRAMELEN 70
|
||||||
#define M20_CRCPOS 22
|
#define M20_CRCPOS 68
|
||||||
|
|
||||||
void M20::printRaw(uint8_t *data, int len)
|
void M20::printRaw(uint8_t *data, int len)
|
||||||
{
|
{
|
||||||
@@ -220,6 +221,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 int16_t getint16_r(uint8_t *data) {
|
||||||
|
return (int16_t)(((uint16_t)data[1]<<8) |data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
static char dez(uint8_t nr) {
|
static char dez(uint8_t nr) {
|
||||||
nr = nr%10;
|
nr = nr%10;
|
||||||
return '0'+nr;
|
return '0'+nr;
|
||||||
@@ -264,49 +269,35 @@ int M20::decodeframeM20(uint8_t *data) {
|
|||||||
}
|
}
|
||||||
Serial.println(crcok?"CRC OK":"CRC NOT OK");
|
Serial.println(crcok?"CRC OK":"CRC NOT OK");
|
||||||
//M20 0x20
|
//M20 0x20
|
||||||
if(data[1]==0x20 && data[2]==0x20) {
|
if(data[1]==0x20) {
|
||||||
Serial.println("Decoding...");
|
Serial.println("Decoding...");
|
||||||
// Its a M20
|
// Its a M20
|
||||||
// getid...
|
// getid...
|
||||||
char ids[11]={'M','E','0','0','0','0','0','0','0','0','0'};
|
char ids[11]={'M','E','0','0','0','0','0','0','0','0','0'};
|
||||||
/*
|
|
||||||
ids[0] = 'M';
|
ids[0] = 'M';
|
||||||
ids[1] = 'E';
|
ids[1] = 'E';
|
||||||
ids[2] = hex(data[95]/16);
|
uint32_t id = getint16(data+18);
|
||||||
ids[3] = hex(data[95]);
|
ids[2] = hex(id/16);
|
||||||
ids[4] = hex(data[93]);
|
ids[3] = hex(id);
|
||||||
uint32_t id = data[96] + data[97]*256;
|
//
|
||||||
ids[5] = hex(id/4096);
|
id = getint16_r(data+19)/4;
|
||||||
ids[6] = hex(id/256);
|
ids[4] = (char)((id/10000)%10+48);
|
||||||
ids[7] = hex(id/16);
|
ids[5] = (char)((id/1000)%10+48);
|
||||||
ids[8] = hex(id);
|
ids[6] = (char)((id/100)%10+48);
|
||||||
ids[9] = 0;
|
ids[7] = (char)((id/10)%10+48);
|
||||||
strncpy(sonde.si()->id, ids, 10);
|
ids[8] = (char)(id%10+48);
|
||||||
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);
|
|
||||||
*/
|
|
||||||
uint32_t id = data[96] + data[97]*256;
|
|
||||||
id &= 0x1fff;
|
|
||||||
strncpy(sonde.si()->ser, ids, 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
|
||||||
// position data
|
// position data
|
||||||
// 0x1C 4 byte
|
// 0x1C 4 byte
|
||||||
// DEGMUL like M10
|
sonde.si()->lat = getint32(data+28) * 1e-6;
|
||||||
sonde.si()->lat = getint32(data+28) * DEGMUL;
|
|
||||||
//0x20 4 byte
|
//0x20 4 byte
|
||||||
sonde.si()->lon = getint32(data+32) * DEGMUL;
|
sonde.si()->lon = getint32(data+32) * 1e-6;
|
||||||
//0x08 3 byte
|
//0x08 3 byte
|
||||||
sonde.si()->alt = getint24(data+8) * 0.01;
|
sonde.si()->alt = getint24(data+8) * VMUL_M20;
|
||||||
//0x0B 2 byte
|
//0x0B 2 byte
|
||||||
//VMUL_M20 specific
|
//VMUL_M20 specific
|
||||||
float ve = getint16(data+11)*VMUL_M20;
|
float ve = getint16(data+11)*VMUL_M20;
|
||||||
@@ -319,20 +310,11 @@ int M20::decodeframeM20(uint8_t *data) {
|
|||||||
if(dir<0) dir+=360;
|
if(dir<0) dir+=360;
|
||||||
sonde.si()->dir = dir;
|
sonde.si()->dir = dir;
|
||||||
sonde.si()->validPos = 0x3f;
|
sonde.si()->validPos = 0x3f;
|
||||||
/*
|
|
||||||
uint32_t gpstime = getint32(data+10);
|
|
||||||
uint16_t gpsweek = getint16(data+32);
|
|
||||||
// UTC is GPSTIME - 18s (24*60*60-18 = 86382)
|
|
||||||
// one week = 7*24*60*60 = 604800 seconds
|
|
||||||
// unix epoch starts jan 1st 1970 0:00
|
|
||||||
// gps time starts jan 6, 1980 0:00. thats 315964800 epoch seconds.
|
|
||||||
// subtracting 86400 yields 315878400UL
|
|
||||||
sonde.si()->time = (gpstime/1000) + 86382 + gpsweek*604800 + 315878400UL;
|
|
||||||
*/
|
|
||||||
//0x0F 3 byte
|
//0x0F 3 byte
|
||||||
uint32_t gpstime = getint24(data+15);
|
uint32_t tow = getint24(data+15);
|
||||||
uint16_t gpsweek = getint16(data+26);
|
uint16_t week = getint16(data+26);
|
||||||
sonde.si()->time = gpstime + 86382 + gpsweek*604800 + 315878400UL;
|
sonde.si()->time = (tow+week*604800+315964800)-18;
|
||||||
|
|
||||||
sonde.si()->validTime = true;
|
sonde.si()->validTime = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -404,7 +386,7 @@ void M20::processM20data(uint8_t dt)
|
|||||||
int M20::receive() {
|
int M20::receive() {
|
||||||
unsigned long t0 = millis();
|
unsigned long t0 = millis();
|
||||||
Serial.printf("M20::receive() start at %ld\n",t0);
|
Serial.printf("M20::receive() start at %ld\n",t0);
|
||||||
while( millis() - t0 < 1000 ) {
|
while( millis() - t0 < 1512 ) {
|
||||||
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||||
if ( bitRead(value, 7) ) {
|
if ( bitRead(value, 7) ) {
|
||||||
Serial.println("FIFO full");
|
Serial.println("FIFO full");
|
||||||
@@ -550,3 +532,4 @@ int oldwaitRXcomplete() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
M20 m20 = M20();
|
M20 m20 = M20();
|
||||||
|
|
||||||
@@ -356,7 +356,8 @@ static void posrs41(const byte b[], uint32_t b_len, uint32_t p)
|
|||||||
if (dir<0.0) dir = 360.0+dir;
|
if (dir<0.0) dir = 360.0+dir;
|
||||||
sonde.si()->dir = dir;
|
sonde.si()->dir = dir;
|
||||||
Serial.print(" ");
|
Serial.print(" ");
|
||||||
sonde.si()->hs = sqrt((float)(vn*vn+ve*ve))*3.6f;
|
//sonde.si()->hs = sqrt((float)(vn*vn+ve*ve))*3.6f;
|
||||||
|
sonde.si()->hs = sqrt((float)(vn*vn+ve*ve));
|
||||||
Serial.print(sonde.si()->hs);
|
Serial.print(sonde.si()->hs);
|
||||||
Serial.print("km/h ");
|
Serial.print("km/h ");
|
||||||
Serial.print(dir);
|
Serial.print(dir);
|
||||||
@@ -429,6 +429,7 @@ void Sonde::setup() {
|
|||||||
break;
|
break;
|
||||||
case STYPE_DFM06:
|
case STYPE_DFM06:
|
||||||
case STYPE_DFM09:
|
case STYPE_DFM09:
|
||||||
|
case STYPE_DFM:
|
||||||
dfm.setup( sondeList[rxtask.currentSonde].freq * 1000000, sondeList[rxtask.currentSonde].type==STYPE_DFM06?0:1 );
|
dfm.setup( sondeList[rxtask.currentSonde].freq * 1000000, sondeList[rxtask.currentSonde].type==STYPE_DFM06?0:1 );
|
||||||
break;
|
break;
|
||||||
case STYPE_RS92:
|
case STYPE_RS92:
|
||||||
@@ -465,6 +466,7 @@ void Sonde::receive() {
|
|||||||
case STYPE_M20:
|
case STYPE_M20:
|
||||||
res = m20.receive();
|
res = m20.receive();
|
||||||
break;
|
break;
|
||||||
|
case STYPE_DFM:
|
||||||
case STYPE_DFM06:
|
case STYPE_DFM06:
|
||||||
case STYPE_DFM09:
|
case STYPE_DFM09:
|
||||||
res = dfm.receive();
|
res = dfm.receive();
|
||||||
@@ -560,6 +562,7 @@ rxloop:
|
|||||||
case STYPE_M20:
|
case STYPE_M20:
|
||||||
m20.waitRXcomplete();
|
m20.waitRXcomplete();
|
||||||
break;
|
break;
|
||||||
|
case STYPE_DFM:
|
||||||
case STYPE_DFM06:
|
case STYPE_DFM06:
|
||||||
case STYPE_DFM09:
|
case STYPE_DFM09:
|
||||||
dfm.waitRXcomplete();
|
dfm.waitRXcomplete();
|
||||||
@@ -46,9 +46,10 @@ extern const char *RXstr[];
|
|||||||
// 01000000 => goto sonde -1
|
// 01000000 => goto sonde -1
|
||||||
// 01000001 => goto sonde +1
|
// 01000001 => goto sonde +1
|
||||||
|
|
||||||
#define NSondeTypes 6
|
#define NSondeTypes 7
|
||||||
enum SondeType { STYPE_DFM06, STYPE_DFM09, STYPE_RS41, STYPE_RS92, STYPE_M10, STYPE_M20 };
|
enum SondeType { STYPE_DFM06, STYPE_DFM09, STYPE_RS41, STYPE_RS92, STYPE_M10, STYPE_M20, STYPE_DFM };
|
||||||
extern const char *sondeTypeStr[NSondeTypes];
|
extern const char *sondeTypeStr[NSondeTypes];
|
||||||
|
extern const char sondeTypeChar[NSondeTypes];
|
||||||
|
|
||||||
typedef struct st_sondeinfo {
|
typedef struct st_sondeinfo {
|
||||||
// receiver configuration
|
// receiver configuration
|
||||||
@@ -56,6 +57,7 @@ typedef struct st_sondeinfo {
|
|||||||
SondeType type;
|
SondeType type;
|
||||||
float freq;
|
float freq;
|
||||||
// decoded ID
|
// decoded ID
|
||||||
|
char typestr[5]; // decoded type (use type if *typestr==0)
|
||||||
char id[10];
|
char id[10];
|
||||||
char ser[12];
|
char ser[12];
|
||||||
bool validID;
|
bool validID;
|
||||||
@@ -69,8 +71,8 @@ typedef struct st_sondeinfo {
|
|||||||
int durvolminute; // duree vol minute
|
int durvolminute; // duree vol minute
|
||||||
int durvolseconde; // duree vol seconde
|
int durvolseconde; // duree vol seconde
|
||||||
float alt; // altitude
|
float alt; // altitude
|
||||||
float vs; // vertical speed
|
float vs; // vertical speed in m/s
|
||||||
float hs; // horizontal speed
|
float hs; // horizontal speed in m/s
|
||||||
float dir; // 0..360
|
float dir; // 0..360
|
||||||
uint8_t sats; // number of sats
|
uint8_t sats; // number of sats
|
||||||
uint8_t validPos; // bit pattern for validity of above 7 fields; 0x80: position is old
|
uint8_t validPos; // bit pattern for validity of above 7 fields; 0x80: position is old
|
||||||
@@ -317,7 +317,7 @@ char *aprs_senddata(SondeInfo *s, const char *usercall, const char *sym) {
|
|||||||
char comm[100];
|
char comm[100];
|
||||||
snprintf(comm, 100, "Clb=%.1fm/s %.3fMHz Type=%s", s->vs, s->freq, sondeTypeStr[s->type]);
|
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) {
|
if(s->type==STYPE_M20||s->type==STYPE_M10||s->type==STYPE_DFM||s->type==STYPE_DFM06||s->type==STYPE_DFM09) {
|
||||||
snprintf(comm, 100, " ser=%s", s->ser);
|
snprintf(comm, 100, " ser=%s", s->ser);
|
||||||
strcat(b, comm);
|
strcat(b, comm);
|
||||||
}
|
}
|
||||||
@@ -136,11 +136,15 @@ void geteph() {
|
|||||||
int len=0;
|
int len=0;
|
||||||
while(dclient.connected()) {
|
while(dclient.connected()) {
|
||||||
while(dclient.available()) {
|
while(dclient.available()) {
|
||||||
char c = dclient.read();
|
int c = dclient.read();
|
||||||
|
if(c==-1) {
|
||||||
|
Serial.println("dclient.read() returned -1 inspite of available() being true?!");
|
||||||
|
} else {
|
||||||
fh.write(c);
|
fh.write(c);
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Serial.printf("fetched %d bytes\n", len);
|
Serial.printf("fetched %d bytes\n", len);
|
||||||
fh.close();
|
fh.close();
|
||||||
snprintf(buf, 16, "Fetched %d B ",len);
|
snprintf(buf, 16, "Fetched %d B ",len);
|
||||||
Reference in New Issue
Block a user