diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino
index d8a4da5..11f8c68 100644
--- a/RX_FSK/RX_FSK.ino
+++ b/RX_FSK/RX_FSK.ino
@@ -40,6 +40,19 @@ boolean connected = false;
WiFiUDP udp;
WiFiClient client;
+
+enum KeyPress { KP_NONE = 0, KP_SHORT, KP_DOUBLE, KP_MID, KP_LONG };
+
+struct Button {
+ uint8_t pin;
+ uint32_t numberKeyPresses;
+ KeyPress pressed;
+ unsigned long press_ts;
+ boolean doublepress;
+};
+Button button1 = {0, 0, KP_NONE, 0, false};
+
+
// Set LED GPIO
int ledPin = 1;
// Stores LED state
@@ -363,6 +376,8 @@ struct st_configitems config_list[] = {
{"timer", "Spectrum Timer", 0, &sonde.config.timer},
{"marker", "Spectrum MHz marker", 0, &sonde.config.marker},
{"noisefloor", "Sepctrum noisefloor", 0, &sonde.config.noisefloor},
+ {"showafc", "Show AFC value", 0, &sonde.config.showafc},
+ {"freqofs", "RX frequency offset (Hz)", 0, &sonde.config.freqofs},
{"---", "---", -1, NULL},
/* APRS settings */
{"call", "Call", 8, sonde.config.call},
@@ -382,6 +397,10 @@ struct st_configitems config_list[] = {
{"tcp.idformat", "DFM ID Format", -2, &sonde.config.tcpfeed.idformat},
{"tcp.highrate", "Rate limit", 0, &sonde.config.tcpfeed.highrate},
{"---", "---", -1, NULL},
+ /* RS41 decoder settings */
+ {"rs41.agcbw", "RS41 AGC bandwidth", 0, &sonde.config.rs41.agcbw},
+ {"rs41.rxbw", "RS41 RX bandwidth", 0, &sonde.config.rs41.rxbw},
+ {"---", "---", -1, NULL},
/* Hardware dependeing settings */
{"oled_sda", "OLED SDA (needs reboot)", 0, &sonde.config.oled_sda},
{"oled_scl", "OLED SCL (needs reboot)", 0, &sonde.config.oled_scl},
@@ -472,6 +491,49 @@ const char *handleConfigPost(AsyncWebServerRequest *request) {
setupConfigData();
}
+const char *ctrlid[]={"rx","scan","spec","wifi"};
+const char *ctrllabel[]={"Receiver (short keypress)", "Scanner (double keypress)", "Spectrum (medium keypress)", "WiFi (long keypress)"};
+const char *createControlForm() {
+ char *ptr = message;
+ char tmp[4];
+ strcpy(ptr, "
");
+ return message;
+}
+
+
+const char *handleControlPost(AsyncWebServerRequest *request) {
+ Serial.println("Handling post request");
+ int params = request->params();
+ for (int i = 0; i < params; i++) {
+ String param = request->getParam(i)->name();
+ Serial.println(param.c_str());
+ if(param.equals("rx")) {
+ Serial.println("equals rx");
+ button1.pressed = KP_SHORT;
+ }
+ else if(param.equals("scan")) {
+ Serial.println("equals scan");
+ button1.pressed = KP_DOUBLE;
+ }
+ else if(param.equals("spec")) {
+ Serial.println("equals spec");
+ button1.pressed = KP_MID;
+ }
+ else if(param.equals("wifi")) {
+ Serial.println("equals wifi");
+ button1.pressed = KP_LONG;
+ }
+ }
+}
+
const char *createUpdateForm(boolean run) {
char *ptr = message;
char tmp[4];
@@ -556,6 +618,14 @@ void SetupAsyncServer() {
request->send(200, "text/html", createUpdateForm(1));
});
+ server.on("/control.html", HTTP_GET, [](AsyncWebServerRequest * request) {
+ request->send(200, "text/html", createControlForm());
+ });
+ server.on("/control.html", HTTP_POST, [](AsyncWebServerRequest * request) {
+ handleControlPost(request);
+ request->send(200, "text/html", createControlForm());
+ });
+
// Route to load style.css file
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(SPIFFS, "/style.css", "text/css");
@@ -613,17 +683,6 @@ const char *fetchWifiPw(const char *id) {
}
-enum KeyPress { KP_NONE = 0, KP_SHORT, KP_DOUBLE, KP_MID, KP_LONG };
-
-struct Button {
- uint8_t pin;
- uint32_t numberKeyPresses;
- KeyPress pressed;
- unsigned long press_ts;
- boolean doublepress;
-};
-Button button1 = {0, 0, KP_NONE, 0, false};
-
void IRAM_ATTR buttonISR() {
if (digitalRead(button1.pin) == 0) { // Button down
if (millis() - button1.press_ts < 500) {
@@ -890,7 +949,9 @@ void loopSpectrum() {
case KP_LONG:
enterMode(ST_WIFISCAN);
return;
- case KP_DOUBLE: /* ignore */ break;
+ case KP_DOUBLE:
+ enterMode(ST_SCANNER);
+ break;
default: break;
}
diff --git a/RX_FSK/data/index.html b/RX_FSK/data/index.html
index 32990b4..b683b03 100644
--- a/RX_FSK/data/index.html
+++ b/RX_FSK/data/index.html
@@ -20,6 +20,7 @@
+
@@ -47,6 +48,11 @@
+
+
Control
+
+
+
About
%VERSION_NAME%
diff --git a/libraries/SX1278FSK/SX1278FSK.cpp b/libraries/SX1278FSK/SX1278FSK.cpp
index 058d8fc..c7b5e29 100644
--- a/libraries/SX1278FSK/SX1278FSK.cpp
+++ b/libraries/SX1278FSK/SX1278FSK.cpp
@@ -330,6 +330,7 @@ uint8_t SX1278FSK::setFrequency(float freq) {
// set mode to FSK STANDBY
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE);
+ freq += sonde.config.freqofs; // manual frequency correction
uint32_t frf = freq * 1.0 * (1<<19) / SX127X_CRYSTAL_FREQ;
writeRegister(REG_FRF_MSB, (frf&0xff0000)>>16);
@@ -533,6 +534,30 @@ int16_t SX1278FSK::getRSSI()
return RSSI;
}
+/*
+Function: Gets the current value of FEI (frequency error indication)
+Returns: FEI value in Hz
+*/
+int32_t SX1278FSK::getFEI()
+{
+ int32_t FEI;
+ int16_t regval = (readRegister(REG_FEI_MSB)<<8) | readRegister(REG_FEI_LSB);
+ Serial.printf("feireg: %04x\n", regval);
+ FEI = (int32_t)(regval * SX127X_FSTEP);
+ return FEI;
+}
+/*
+Function: Gets the current value of AFC (automated frequency correction)
+Returns: AFC value in Hz
+*/
+int32_t SX1278FSK::getAFC()
+{
+ int32_t AFC;
+ int16_t regval = (readRegister(REG_AFC_MSB)<<8) | readRegister(REG_AFC_LSB);
+ Serial.printf("afcreg: %04x\n", regval);
+ AFC = (int32_t)(regval * SX127X_FSTEP);
+ return AFC;
+}
/*
Function: Gets the current supply limit of the power amplifier, protecting battery chemistries.
@@ -693,8 +718,13 @@ uint8_t SX1278FSK::receivePacketTimeout(uint32_t wait, byte *data)
data[di++] = readRegister(REG_FIFO);
if(di==1) {
int rssi=getRSSI();
+ int fei=getFEI();
+ int afc=getAFC();
Serial.print("Test: RSSI="); Serial.println(rssi);
+ Serial.print("Test: FEI="); Serial.println(fei);
+ Serial.print("Test: AFC="); Serial.println(afc);
sonde.si()->rssi = rssi;
+ sonde.si()->afc = afc;
}
if(di>520) {
// TODO
diff --git a/libraries/SX1278FSK/SX1278FSK.h b/libraries/SX1278FSK/SX1278FSK.h
index 16d8dcb..3cb358a 100644
--- a/libraries/SX1278FSK/SX1278FSK.h
+++ b/libraries/SX1278FSK/SX1278FSK.h
@@ -31,6 +31,7 @@
*****************************************************************************/
#define SX127X_CRYSTAL_FREQ 32000000
+#define SX127X_FSTEP (SX127X_CRYSTAL_FREQ*1.0/(1<<19))
#define SX1278FSK_debug_mode 0
@@ -234,6 +235,12 @@ public:
// Get current RSSI value
int16_t getRSSI();
+ // Get current FEI (frequency error indication) value
+ int32_t getFEI();
+
+ // Get current AFC value
+ int32_t getAFC();
+
// Get the maximum current supply by the module.
int getMaxCurrent();
diff --git a/libraries/SondeLib/RS41.cpp b/libraries/SondeLib/RS41.cpp
index 586698a..233a5d9 100644
--- a/libraries/SondeLib/RS41.cpp
+++ b/libraries/SondeLib/RS41.cpp
@@ -98,11 +98,11 @@ int RS41::setup()
Serial.println(br);
#endif
- if(sx1278.setAFCBandwidth(25000)!=0) {
+ if(sx1278.setAFCBandwidth(sonde.config.rs41.agcbw)!=0) {
RS41_DBG(Serial.println("Setting AFC bandwidth 25 kHz FAILED"));
return 1;
}
- if(sx1278.setRxBandwidth(12000)!=0) {
+ if(sx1278.setRxBandwidth(sonde.config.rs41.rxbw)!=0) {
RS41_DBG(Serial.println("Setting RX bandwidth 12kHz FAILED"));
return 1;
}
diff --git a/libraries/SondeLib/Sonde.cpp b/libraries/SondeLib/Sonde.cpp
index c475cd0..dedeee5 100644
--- a/libraries/SondeLib/Sonde.cpp
+++ b/libraries/SondeLib/Sonde.cpp
@@ -4,8 +4,10 @@
#include "Sonde.h"
#include "RS41.h"
#include "DFM.h"
+#include "SX1278FSK.h"
extern U8X8_SSD1306_128X64_NONAME_SW_I2C *u8x8;
+extern SX1278FSK sx1278;
//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" };
@@ -74,6 +76,11 @@ Sonde::Sonde() {
config.spectrum=10;
config.timer=0;
config.marker=0;
+ config.norx_timeout=0;
+ config.showafc=0;
+ config.freqofs=0;
+ config.rs41.agcbw=25;
+ config.rs41.rxbw=12;
config.udpfeed.active = 1;
config.udpfeed.type = 0;
strcpy(config.udpfeed.host, "192.168.42.20");
@@ -135,6 +142,16 @@ void Sonde::setConfig(const char *cfg) {
config.timer = atoi(val);
} else if(strcmp(cfg,"marker")==0) {
config.marker = atoi(val);
+ } else if(strcmp(cfg,"norx_timeout")==0) {
+ config.norx_timeout = atoi(val);
+ } else if(strcmp(cfg,"showafc")==0) {
+ config.showafc = atoi(val);
+ } else if(strcmp(cfg,"freqofs")==0) {
+ config.freqofs = atoi(val);
+ } else if(strcmp(cfg,"rs41.agcbw")==0) {
+ config.rs41.agcbw = atoi(val);
+ } else if(strcmp(cfg,"rs41.rxbw")==0) {
+ config.rs41.rxbw = atoi(val);
} else if(strcmp(cfg,"axudp.active")==0) {
config.udpfeed.active = atoi(val)>0;
} else if(strcmp(cfg,"axudp.host")==0) {
@@ -235,6 +252,11 @@ void Sonde::setup() {
dfm.setFrequency(sondeList[currentSonde].freq * 1000000);
break;
}
+ // debug
+ float afcbw = sx1278.getAFCBandwidth();
+ float rxbw = sx1278.getRxBandwidth();
+ Serial.printf("AFC BW: %f RX BW: %f\n", afcbw, rxbw);
+
}
int Sonde::receiveFrame() {
int ret;
@@ -317,6 +339,10 @@ void Sonde::updateDisplayRXConfig() {
u8x8->drawString(0,0, sondeTypeStr[si()->type]);
snprintf(buf, 16, "%3.3f MHz", si()->freq);
u8x8->drawString(5,0, buf);
+ if(config.showafc) {
+ snprintf(buf, 15, " %+3.2fk", si()->afc*0.001);
+ u8x8->drawString(8,1,buf+strlen(buf)-8);
+ }
//snprintf(buf, 8, "%s", si()->launchsite);
//u8x8->drawString(0,5, buf);
}
diff --git a/libraries/SondeLib/Sonde.h b/libraries/SondeLib/Sonde.h
index 9eaed1b..f35a8b8 100644
--- a/libraries/SondeLib/Sonde.h
+++ b/libraries/SondeLib/Sonde.h
@@ -12,6 +12,11 @@ enum RxResult { RX_OK, RX_TIMEOUT, RX_ERROR, RX_UNKNOWN };
enum SondeType { STYPE_DFM06, STYPE_DFM09, STYPE_RS41 };
extern const char *sondeTypeStr[5];
+struct st_rs41config {
+ int agcbw;
+ int rxbw;
+};
+
typedef struct st_rdzconfig {
int button_pin; // PIN port number menu button (for some boards)
int led_pout; // POUT port number of LED (used as serial monitor)
@@ -27,9 +32,13 @@ typedef struct st_rdzconfig {
int timer; // show remaining time in spectrum 0=disable
int marker; // show freq marker in spectrum 0=disable
int maxsonde; // number of max sonde in scan (range=1-99)
+ int norx_timeout; // Time after which rx mode switches to scan mode (without rx signal)
int noisefloor; // for spectrum display
+ int showafc; // show afc value in rx screen
+ int freqofs; // frequency offset (tuner config = rx frequency + freqofs) in Hz
char call[9]; // APRS callsign
char passcode[9]; // APRS passcode
+ struct st_rs41config rs41; // configuration options specific for RS41 receiver
// for now, one feed for each type is enough, but might get extended to more?
struct st_feedinfo udpfeed; // target for AXUDP messages
struct st_feedinfo tcpfeed; // target for APRS-IS TCP connections
@@ -54,6 +63,7 @@ typedef struct st_sondeinfo {
uint8_t validPos; // bit pattern for validity of above 6 fields
// RSSI from receiver
int rssi; // signal strength
+ int32_t afc; // afc correction value
uint8_t rxStat[20];
} SondeInfo;
// rxState: 0=undef[empty] 1=timeout[.] 2=errro[E] 3=ok[1]