not or it but ADD IT? THIS WAS NOT WRITTEN BY AI, THIS IS CLOWN PRODUCTION

This commit is contained in:
2026-01-05 19:30:23 +01:00
parent bfe5a41ea3
commit 8d76a0054f
12 changed files with 401 additions and 581 deletions
+4 -7
View File
@@ -21,7 +21,6 @@ enum RDS_GROUPS {
// Fixed PI/callsign combinations for Canada // Fixed PI/callsign combinations for Canada
static const uint16_t fixedPI[] = {0x4C10, 0x4C11, 0x4C12}; static const uint16_t fixedPI[] = {0x4C10, 0x4C11, 0x4C12};
static const char* fixedCalls[] = {"CBLA", "CBFM", "CBOT"};
static const char* const PTY_EU[] { static const char* const PTY_EU[] {
"None", "None",
@@ -433,11 +432,9 @@ const DABFrequencyLabel DABfrequencyTable[] = {
{1490624, "LW"} {1490624, "LW"}
}; };
#pragma GCC diagnostic pop
typedef struct _rds_ { typedef struct _rds_ {
byte region; byte region;
byte stationTypeCode; byte PTY;
String stationName; String stationName;
String stationText; String stationText;
String stationText32; String stationText32;
@@ -480,7 +477,7 @@ typedef struct _rds_ {
bool hasLongPS; bool hasLongPS;
bool hasRT; bool hasRT;
bool hasEnhancedRT; bool hasEnhancedRT;
bool hasTP; bool TP;
bool hasTA; bool hasTA;
bool hasEON; bool hasEON;
bool hasAID; bool hasAID;
@@ -490,7 +487,7 @@ typedef struct _rds_ {
bool hasPTYN; bool hasPTYN;
bool rtAB; bool rtAB;
bool rtAB32; bool rtAB32;
bool hasRDSplus; bool hasRTplus;
bool filter; bool filter;
bool rdsreset; bool rdsreset;
bool pierrors; bool pierrors;
@@ -590,7 +587,7 @@ class TEF6686 {
uint8_t af_counter; uint8_t af_counter;
uint8_t eon_counter; uint8_t eon_counter;
uint8_t logbook_counter; uint8_t logbook_counter;
uint8_t rdsblock; uint8_t rdsgroup;
unsigned long processed_rdsblocks; unsigned long processed_rdsblocks;
bool mute; bool mute;
bool afmethodB; bool afmethodB;
+8 -8
View File
@@ -8,15 +8,15 @@
* GNU General Public License v3.0 licence, all text here must be included in any redistribution and you should receive a copy of the license file. * GNU General Public License v3.0 licence, all text here must be included in any redistribution and you should receive a copy of the license file.
* *
*/ */
#ifndef WC_AP_HTML #ifndef WC_AP_HTML
#define WC_AP_HTML ///< Define to stop re-inclusion #define WC_AP_HTML ///< Define to stop re-inclusion
/*! \def char AP_HTTP_HEAD[] PROGMEM /*! \def char AP_HTTP_HEAD[] PROGMEM
Start of HTML output Start of HTML output
*/ */
const char AP_HTTP_HEAD[] PROGMEM = "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/><title>{v}</title>"; const char AP_HTTP_HEAD[] PROGMEM = "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/><title>{v}</title>";
/*! \def AP_HTTP_STYLE[] PROGMEM /*! \def AP_HTTP_STYLE[] PROGMEM
Style for our access point Style for our access point
*/ */
const char AP_HTTP_STYLE[] PROGMEM = "<style type=\"text/css\">h1 { font-weight: normal; } .msgbox { font-size:1.2rem; line-height: 1.8em; padding: 0.5em; background-color: #ddffff; border-left: 6px solid #ccc; margin-bottom:1em; } .c{text-align:center}div,input{padding:5px;font-size:1em}input{width:95%;margin-top:5px;margin-bottom:10px}body{text-align:center;font-family:verdana;}button{border:0;border-radius:.3rem;background-color:#1fa3ec;color:#fff;line-height:2.6rem;font-size:1.2rem;width:100%}.q{float:right;width:64px;text-align:right}.l{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAALVBMVEX///8EBwfBwsLw8PAzNjaCg4NTVVUjJiZDRUUUFxdiZGSho6OSk5Pg4eFydHTCjaf3AAAAZElEQVQ4je2NSw7AIAhEBamKn97/uMXEGBvozkWb9C2Zx4xzWykBhFAeYp9gkLyZE0zIMno9n4g19hmdY39scwqVkOXaxph0ZCXQcqxSpgQpONa59wkRDOL93eAXvimwlbPbwwVAegLS1HGfZAAAAABJRU5ErkJggg==) no-repeat left center;background-size:1em;}.cfail,.cok{text-align:center; font-size:1.2rem; line-height: 2em; margin-top: 1em; padding: 0.7em; display:none;} .cfail{color: #FFFFFF;background-color: #ff8433;} .cok{ background-color: #6aff33;}</style>"; const char AP_HTTP_STYLE[] PROGMEM = "<style type=\"text/css\">h1 { font-weight: normal; } .msgbox { font-size:1.2rem; line-height: 1.8em; padding: 0.5em; background-color: #ddffff; border-left: 6px solid #ccc; margin-bottom:1em; } .c{text-align:center}div,input{padding:5px;font-size:1em}input{width:95%;margin-top:5px;margin-bottom:10px}body{text-align:center;font-family:verdana;}button{border:0;border-radius:.3rem;background-color:#1fa3ec;color:#fff;line-height:2.6rem;font-size:1.2rem;width:100%}.q{float:right;width:64px;text-align:right}.l{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAALVBMVEX///8EBwfBwsLw8PAzNjaCg4NTVVUjJiZDRUUUFxdiZGSho6OSk5Pg4eFydHTCjaf3AAAAZElEQVQ4je2NSw7AIAhEBamKn97/uMXEGBvozkWb9C2Zx4xzWykBhFAeYp9gkLyZE0zIMno9n4g19hmdY39scwqVkOXaxph0ZCXQcqxSpgQpONa59wkRDOL93eAXvimwlbPbwwVAegLS1HGfZAAAAABJRU5ErkJggg==) no-repeat left center;background-size:1em;}.cfail,.cok{text-align:center; font-size:1.2rem; line-height: 2em; margin-top: 1em; padding: 0.7em; display:none;} .cfail{color: #FFFFFF;background-color: #ff8433;} .cok{ background-color: #6aff33;}</style>";
/** Scripts for our page */ /** Scripts for our page */
@@ -40,18 +40,18 @@ const char AP_HTTP_SCAN_LINK[] PROGMEM = "<br/><div class=\"c\"><a href=\"
// https://esprima.org/demo/validate.html // https://esprima.org/demo/validate.html
// https://javascript-minifier.com/ // https://javascript-minifier.com/
/* Use JavaScript to ping the ESP periodically @ the AP IP address. /* Use JavaScript to ping the ESP periodically @ the AP IP address.
* If it comes back as an AP again then we know the connection to the WiFi didn't work. * If it comes back as an AP again then we know the connection to the WiFi didn't work.
* We wait about 30 seconds to determine this outcome. This isn't 100% foolproof, but should be good enough. * We wait about 30 seconds to determine this outcome. This isn't 100% foolproof, but should be good enough.
*/ */
/* /*
<script type="text/javascript"> <script type="text/javascript">
function doPing() { function doPing() {
//if ( timeout_count > 20 ) { //if ( timeout_count > 20 ) {
if ( attempt_count > 20 ) { // wait about a minute if ( attempt_count > 20 ) { // wait about a minute
window.clearInterval(myPinger), document.getElementById("conn_ok").style.display = "block" window.clearInterval(myPinger), document.getElementById("conn_ok").style.display = "block"
} }
var o = new XMLHttpRequest; var o = new XMLHttpRequest;
o.onload = function() { o.onload = function() {
console.log(this.responseText), document.getElementById("conn_fail").style.display = "block", window.clearInterval(myPinger) console.log(this.responseText), document.getElementById("conn_fail").style.display = "block", window.clearInterval(myPinger)
@@ -59,7 +59,7 @@ function doPing() {
console.log("Timeout Counter is: " + timeout_count++) console.log("Timeout Counter is: " + timeout_count++)
}, o.open("GET", "/foo"), o.timeout = 1000, o.send(null), console.log("Ping counter is: " + attempt_count++) }, o.open("GET", "/foo"), o.timeout = 1000, o.send(null), console.log("Ping counter is: " + attempt_count++)
} }
attempt_count = 0; attempt_count = 0;
timeout_count = 0; timeout_count = 0;
var myPinger = window.setInterval(doPing, 3000); var myPinger = window.setInterval(doPing, 3000);
+5 -23
View File
@@ -1,10 +1,5 @@
#pragma GCC diagnostic push #define VERSION "v2.20.5b"
#pragma GCC diagnostic ignored "-Wunused-variable"
#define VERSION "v2.20.5"
#define ON 1
#define OFF 0
#define REVERSE false #define REVERSE false
#define ALEFT -1 #define ALEFT -1
@@ -362,13 +357,6 @@
#endif #endif
// End of EEPROM index defines // End of EEPROM index defines
static const char* const unitString[] = {"dBμV", "dBf", "dBm"};
static const char* const FreqFont[] = {"Classic", "Roubenstil", "Motoya", "Aura2", "Modern"};
static const char* const Theme[] = {"Essence", "Cyan", "Crimson", "Monochrome", "Volcano", "Dendro", "Sakura", "Whiteout", "Tangerine", "Ocean", "Indigo", "Queer", "GoldBrite", "Bubblegum"};
static const char* const Skin[] = {"Essential"};
static const char* BWButtonLabelsFM[] = {"56 kHz", "64 kHz", "72 kHz", "84 kHz", "97 kHz", "114 kHz", "133 kHz", "151 kHz", "168 kHz", "184 kHz", "200 kHz", "217 kHz", "236 kHz", "254 kHz", "287 kHz", "311 kHz", "Auto", "iMS", "EQ"};
static const char* BWButtonLabelsAM[] = {"3 kHz", "4 kHz", "6 kHz", "8 kHz"};
// Memory channel database // Memory channel database
typedef struct { typedef struct {
byte bw; byte bw;
@@ -383,24 +371,21 @@ enum LONGBANDBUTTONPRESS {
STANDBY = 0, SCREENOFF STANDBY = 0, SCREENOFF
}; };
enum menupage {INDEX, MAINSETTINGS, AUDIOSETTINGS, DISPLAYSETTINGS, RDSSETTINGS, FMSETTINGS, AMSETTINGS, CONNECTIVITY, DXMODE, AUTOMEM enum menupage {INDEX, MAINSETTINGS, AUDIOSETTINGS, DISPLAYSETTINGS, RDSSETTINGS, FMSETTINGS, AMSETTINGS, CONNECTIVITY, DXMODE, AUTOMEM};
};
enum AUTOMEMPIMODES { enum AUTOMEMPIMODES {
MEMPI_OFF = 0, MEMPI_RANGE, MEMPI_FULL MEMPI_OFF = 0, MEMPI_RANGE, MEMPI_FULL
}; };
enum SCAN_CANCEL { enum SCAN_CANCEL {
SCAN_CANCEL = OFF, CORRECTPI, SIGNAL SCAN_CANCEL = 0, CORRECTPI, SIGNAL
}; };
// FM band: before BAND_GAP; AM band: after BAND_GAP
enum RADIO_BAND { enum RADIO_BAND {
BAND_OIRT = 0, BAND_FM, BAND_GAP, BAND_LW, BAND_MW, BAND_SW, BAND_AIR BAND_OIRT = 0, BAND_FM, BAND_GAP, BAND_LW, BAND_MW, BAND_SW, BAND_AIR
}; };
#ifndef HAS_AIR_BAND #ifndef HAS_AIR_BAND
// Toggle: LW -> MW -> SW
enum RADIO_AM_BAND_SELECTION { enum RADIO_AM_BAND_SELECTION {
AM_BAND_ALL = 0, AM_BAND_LW_MW, AM_BAND_LW_SW, AM_BAND_MW_SW, AM_BAND_ALL = 0, AM_BAND_LW_MW, AM_BAND_LW_SW, AM_BAND_MW_SW,
AM_BAND_LW, AM_BAND_MW, AM_BAND_SW, AM_BAND_NONE, AM_BAND_LW, AM_BAND_MW, AM_BAND_SW, AM_BAND_NONE,
@@ -417,9 +402,8 @@ enum RADIO_AM_BAND_SELECTION {
AM_BAND_LW, AM_BAND_MW, AM_BAND_SW, AM_BAND_AIR, AM_BAND_NONE, AM_BAND_LW, AM_BAND_MW, AM_BAND_SW, AM_BAND_AIR, AM_BAND_NONE,
AM_BAND_CNT AM_BAND_CNT
}; };
#endif /* end of HAS_AIR_BAND */ #endif
// Toggle: OIRT -> FM
enum RADIO_FM_BAND_SELECTION { enum RADIO_FM_BAND_SELECTION {
FM_BAND_ALL = 0, FM_BAND_OIRT, FM_BAND_FM, FM_BAND_NONE, FM_BAND_ALL = 0, FM_BAND_OIRT, FM_BAND_FM, FM_BAND_NONE,
FM_BAND_CNT FM_BAND_CNT
@@ -792,6 +776,4 @@ static const uint16_t openradiologo[] PROGMEM = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xbdf7, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffdf, 0x39c7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x42e6, 0x76ef, 0xa6cf, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x7ecf, 0x5be9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xce59, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xef5d, 0x3186, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xbdf7, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffdf, 0x39c7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x42e6, 0x76ef, 0xa6cf, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x7ecf, 0x5be9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xce59, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xef5d, 0x3186, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x9492, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5367, 0x76ef, 0x9e6e, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x1962, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x31a6, 0xef7d, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xef5d, 0x4228, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc618, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x9492, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5367, 0x76ef, 0x9e6e, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x1962, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x31a6, 0xef7d, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xef5d, 0x4228, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xad75, 0xf7be, 0xffff, 0xffff, 0xffff, 0xffff, 0xef7d, 0x94b2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2183, 0x5be8, 0x76ef, 0x95ed, 0x9e8f, 0xa6ef, 0xa730, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0xa730, 0xa6f0, 0x9e8f, 0x962e, 0x76ef, 0x76ef, 0x3aa5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4208, 0xd6ba, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xd6ba, 0x2965, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xad75, 0xf7be, 0xffff, 0xffff, 0xffff, 0xffff, 0xef7d, 0x94b2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2183, 0x5be8, 0x76ef, 0x95ed, 0x9e8f, 0xa6ef, 0xa730, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0x76ef, 0xa730, 0xa6f0, 0x9e8f, 0x962e, 0x76ef, 0x76ef, 0x3aa5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4208, 0xd6ba, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xd6ba, 0x2965, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
}; };
#pragma GCC diagnostic pop
+7
View File
@@ -8,6 +8,13 @@
#include "WiFiConnectParam.h" #include "WiFiConnectParam.h"
#include "menugraphics.h" #include "menugraphics.h"
static const char* const unitString[] = {"dBμV", "dBf", "dBm"};
static const char* const FreqFont[] = {"Classic", "Roubenstil", "Motoya", "Aura2", "Modern"};
static const char* const Theme[] = {"Essence", "Cyan", "Crimson", "Monochrome", "Volcano", "Dendro", "Sakura", "Whiteout", "Tangerine", "Ocean", "Indigo", "Queer", "GoldBrite", "Bubblegum"};
static const char* const Skin[] = {"Essential"};
static const char* BWButtonLabelsFM[] = {"56 kHz", "64 kHz", "72 kHz", "84 kHz", "97 kHz", "114 kHz", "133 kHz", "151 kHz", "168 kHz", "184 kHz", "200 kHz", "217 kHz", "236 kHz", "254 kHz", "287 kHz", "311 kHz", "Auto", "iMS", "EQ"};
static const char* BWButtonLabelsAM[] = {"3 kHz", "4 kHz", "6 kHz", "8 kHz"};
#define SMETERPIN 27 #define SMETERPIN 27
#define CONTRASTPIN 2 #define CONTRASTPIN 2
+17
View File
@@ -0,0 +1,17 @@
{
"name": "Hash",
"version": "1.0",
"description": "Generate Hash from data",
"authors":
[
{
"name": "Markus Sattler",
"maintainer": true
}
],
"frameworks": "arduino",
"platforms": "espressif8266, espressif32",
"build": {
"flags": ["-Wno-unused-function"]
}
}
+4 -6
View File
@@ -793,12 +793,10 @@ bool TFT_eSPI::initDMA(bool ctrl_cs)
.sclk_io_num = TFT_SCLK, .sclk_io_num = TFT_SCLK,
.quadwp_io_num = -1, .quadwp_io_num = -1,
.quadhd_io_num = -1, .quadhd_io_num = -1,
#ifdef xCONFIG_IDF_TARGET_ESP32S2 .data4_io_num = -1,
.data4_io_num = -1, .data5_io_num = -1,
.data5_io_num = -1, .data6_io_num = -1,
.data6_io_num = -1, .data7_io_num = -1,
.data7_io_num = -1,
#endif
.max_transfer_sz = TFT_WIDTH * TFT_HEIGHT * 2 + 8, // TFT screen size .max_transfer_sz = TFT_WIDTH * TFT_HEIGHT * 2 + 8, // TFT screen size
.flags = 0, .flags = 0,
.intr_flags = 0 .intr_flags = 0
+4
View File
@@ -13,3 +13,7 @@ platform = espressif32
board = esp32dev board = esp32dev
framework = arduino framework = arduino
board_build.partitions = huge_app.csv board_build.partitions = huge_app.csv
build_flags =
-Wall
-Wextra
-Wno-unknown-pragmas
+269 -328
View File
@@ -159,7 +159,7 @@ void TEF6686::init(byte TEF) {
void TEF6686::getIdentification(uint16_t *device, uint16_t *hw_version, uint16_t *sw_version) { void TEF6686::getIdentification(uint16_t *device, uint16_t *hw_version, uint16_t *sw_version) {
uint8_t buf[6]; uint8_t buf[6];
uint16_t r = devTEF_Get_Cmd(TEF_APPL, Cmd_Get_Identification, buf, sizeof(buf)); devTEF_Get_Cmd(TEF_APPL, Cmd_Get_Identification, buf, sizeof(buf));
*device = Convert8bto16b(buf); *device = Convert8bto16b(buf);
*hw_version = Convert8bto16b(buf + 2); *hw_version = Convert8bto16b(buf + 2);
@@ -363,10 +363,8 @@ void TEF6686::getStatusAM(int16_t &level, uint16_t &noise, uint16_t &cochannel,
} }
void TEF6686::readRDS(byte showrdserrors) { void TEF6686::readRDS(byte showrdserrors) {
uint8_t offset; if (rds.filter && ps_process) devTEF_Radio_Get_RDS_Status(&rds.rdsStat, &rds.rdsA, &rds.rdsB, &rds.rdsC, &rds.rdsD, &rds.rdsErr);
if (rds.filter && ps_process) { else {
devTEF_Radio_Get_RDS_Status(&rds.rdsStat, &rds.rdsA, &rds.rdsB, &rds.rdsC, &rds.rdsD, &rds.rdsErr);
} else {
if (millis() >= rdstimer + 87) { if (millis() >= rdstimer + 87) {
rdstimer += 87; rdstimer += 87;
devTEF_Radio_Get_RDS_Data(&rds.rdsStat, &rds.rdsA, &rds.rdsB, &rds.rdsC, &rds.rdsD, &rds.rdsErr); devTEF_Radio_Get_RDS_Data(&rds.rdsStat, &rds.rdsA, &rds.rdsB, &rds.rdsC, &rds.rdsD, &rds.rdsErr);
@@ -378,14 +376,11 @@ void TEF6686::readRDS(byte showrdserrors) {
} }
if (bitRead(rds.rdsStat, 9)) { if (bitRead(rds.rdsStat, 9)) {
rds.hasRDS = true; // RDS decoder synchronized and data available rds.hasRDS = true;
bitStartTime = 0; bitStartTime = 0;
} else { } else {
if (bitStartTime == 0) { if (bitStartTime == 0) bitStartTime = millis();
bitStartTime = millis(); else if (millis() - bitStartTime >= 87) rds.hasRDS = false;
} else if (millis() - bitStartTime >= 87) {
rds.hasRDS = false;
}
} }
rdsAerrorThreshold = (((rds.rdsErr >> 14) & 0x03) > showrdserrors); rdsAerrorThreshold = (((rds.rdsErr >> 14) & 0x03) > showrdserrors);
@@ -394,12 +389,11 @@ void TEF6686::readRDS(byte showrdserrors) {
rdsDerrorThreshold = (((rds.rdsErr >> 8) & 0x03) > showrdserrors); rdsDerrorThreshold = (((rds.rdsErr >> 8) & 0x03) > showrdserrors);
if (bitRead(rds.rdsStat, 9) && (rds.rdsA != previous_rdsA || rds.rdsB != previous_rdsB || rds.rdsC != previous_rdsC || rds.rdsD != previous_rdsD)) { if (bitRead(rds.rdsStat, 9) && (rds.rdsA != previous_rdsA || rds.rdsB != previous_rdsB || rds.rdsC != previous_rdsC || rds.rdsD != previous_rdsD)) {
rds.rdsAerror = (((rds.rdsErr >> 14) & 0x03) > 1); // We have all data to decode... let's go... rds.rdsAerror = (((rds.rdsErr >> 14) & 0x03) > 1);
rds.rdsBerror = (((rds.rdsErr >> 12) & 0x03) > 1); rds.rdsBerror = (((rds.rdsErr >> 12) & 0x03) > 1);
rds.rdsCerror = (((rds.rdsErr >> 10) & 0x03) > 1); rds.rdsCerror = (((rds.rdsErr >> 10) & 0x03) > 1);
rds.rdsDerror = (((rds.rdsErr >> 8) & 0x03) > 1); rds.rdsDerror = (((rds.rdsErr >> 8) & 0x03) > 1);
//PI decoder
if (!rdsAerrorThreshold && afreset) { if (!rdsAerrorThreshold && afreset) {
rds.correctPI = rds.rdsA; rds.correctPI = rds.rdsA;
afreset = false; afreset = false;
@@ -413,11 +407,8 @@ void TEF6686::readRDS(byte showrdserrors) {
rds.picode[2] = (rds.rdsA >> 4) & 0xF; rds.picode[2] = (rds.rdsA >> 4) & 0xF;
rds.picode[3] = rds.rdsA & 0xF; rds.picode[3] = rds.rdsA & 0xF;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (rds.picode[i] < 10) { if (rds.picode[i] < 10) rds.picode[i] += '0';
rds.picode[i] += '0'; else rds.picode[i] += 'A' - 10;
} else {
rds.picode[i] += 'A' - 10;
}
} }
} }
@@ -438,7 +429,6 @@ void TEF6686::readRDS(byte showrdserrors) {
if (strncmp(rds.picode, "0000", 4) == 0 && rds.rdsB == 0 && rds.stationName.length() == 0) memset(rds.picode, 0, sizeof(rds.picode)); if (strncmp(rds.picode, "0000", 4) == 0 && rds.rdsB == 0 && rds.stationName.length() == 0) memset(rds.picode, 0, sizeof(rds.picode));
// USA Station callsign decoder // USA Station callsign decoder
if ((rds.region == 1 ? ps_process : true) && rds.correctPI != 0 && rds.region > 0 && correctPIold != rds.correctPI) { if ((rds.region == 1 ? ps_process : true) && rds.correctPI != 0 && rds.region > 0 && correctPIold != rds.correctPI) {
bool foundMatch = false; bool foundMatch = false;
@@ -446,27 +436,16 @@ void TEF6686::readRDS(byte showrdserrors) {
if (rds.region == 1 && SPIFFS.begin(true)) { if (rds.region == 1 && SPIFFS.begin(true)) {
delay(5); delay(5);
if (currentfreq2 < 9000) { if (currentfreq2 < 9000) file = SPIFFS.open("/USA_87-90.csv");
file = SPIFFS.open("/USA_87-90.csv"); else if (currentfreq2 > 9000 && currentfreq2 < 9200) file = SPIFFS.open("/USA_90-92.csv");
} else if (currentfreq2 > 9000 && currentfreq2 < 9200) { else if (currentfreq2 > 9200 && currentfreq2 < 9400) file = SPIFFS.open("/USA_92-94.csv");
file = SPIFFS.open("/USA_90-92.csv"); else if (currentfreq2 > 9400 && currentfreq2 < 9600) file = SPIFFS.open("/USA_94-96.csv");
} else if (currentfreq2 > 9200 && currentfreq2 < 9400) { else if (currentfreq2 > 9600 && currentfreq2 < 9800) file = SPIFFS.open("/USA_96-98.csv");
file = SPIFFS.open("/USA_92-94.csv"); else if (currentfreq2 > 9800 && currentfreq2 < 10000) file = SPIFFS.open("/USA_98-100.csv");
} else if (currentfreq2 > 9400 && currentfreq2 < 9600) { else if (currentfreq2 > 10000 && currentfreq2 < 10200) file = SPIFFS.open("/USA_100-102.csv");
file = SPIFFS.open("/USA_94-96.csv"); else if (currentfreq2 > 10200 && currentfreq2 < 10400) file = SPIFFS.open("/USA_102-104.csv");
} else if (currentfreq2 > 9600 && currentfreq2 < 9800) { else if (currentfreq2 > 10400 && currentfreq2 < 10600) file = SPIFFS.open("/USA_104-106.csv");
file = SPIFFS.open("/USA_96-98.csv"); else if (currentfreq2 > 10600) file = SPIFFS.open("/USA_106-108.csv");
} else if (currentfreq2 > 9800 && currentfreq2 < 10000) {
file = SPIFFS.open("/USA_98-100.csv");
} else if (currentfreq2 > 10000 && currentfreq2 < 10200) {
file = SPIFFS.open("/USA_100-102.csv");
} else if (currentfreq2 > 10200 && currentfreq2 < 10400) {
file = SPIFFS.open("/USA_102-104.csv");
} else if (currentfreq2 > 10400 && currentfreq2 < 10600) {
file = SPIFFS.open("/USA_104-106.csv");
} else if (currentfreq2 > 10600) {
file = SPIFFS.open("/USA_106-108.csv");
}
delay(5); delay(5);
if (file) { if (file) {
@@ -562,43 +541,48 @@ void TEF6686::readRDS(byte showrdserrors) {
} }
} }
if (!rds.rdsBerror || showrdserrors == 3) rdsblock = rds.rdsB >> 11; else return; if(rdsBerrorThreshold) goto end;
rds.blockcounter[rdsblock]++;
rds.TP = (bitRead(rds.rdsB, 10));
rds.PTY = (rds.rdsB >> 5) & 0x1F;
strcpy(rds.stationType, rds.region == 0 ? PTY_EU[rds.PTY] : PTY_USA[rds.PTY]);
if (!rds.rdsBerror || showrdserrors == 3) rdsgroup = rds.rdsB >> 11; else return;
rds.blockcounter[rdsgroup]++;
processed_rdsblocks++; processed_rdsblocks++;
switch (rdsblock) { switch (rdsgroup) {
case RDS_GROUP_0A: case RDS_GROUP_0A:
case RDS_GROUP_0B: case RDS_GROUP_0B:
{ {
//PS decoder if (showrdserrors == 3 || !rdsDerrorThreshold) {
if (showrdserrors == 3 || (!rdsBerrorThreshold && (!rdsDerrorThreshold))) { uint8_t segment = rds.rdsB & 0x03;
offset = rds.rdsB & 0x03; // Let's get the character offset for PS
switch (offset) { switch (segment) {
case 0: if (((rds.rdsErr >> 8) & 0x03) > 1) rds.ps12error = true; else rds.ps12error = false; break; case 0: if (((rds.rdsErr >> 8) & 0x03) > 1) rds.ps12error = true; else rds.ps12error = false; break;
case 1: if (((rds.rdsErr >> 8) & 0x03) > 1) rds.ps34error = true; else rds.ps34error = false; break; case 1: if (((rds.rdsErr >> 8) & 0x03) > 1) rds.ps34error = true; else rds.ps34error = false; break;
case 2: if (((rds.rdsErr >> 8) & 0x03) > 1) rds.ps56error = true; else rds.ps56error = false; break; case 2: if (((rds.rdsErr >> 8) & 0x03) > 1) rds.ps56error = true; else rds.ps56error = false; break;
case 3: if (((rds.rdsErr >> 8) & 0x03) > 1) rds.ps78error = true; else rds.ps78error = false; break; case 3: if (((rds.rdsErr >> 8) & 0x03) > 1) rds.ps78error = true; else rds.ps78error = false; break;
} }
ps_buffer2[(offset * 2) + 0] = ps_buffer[(offset * 2) + 0]; // Make a copy of the PS buffer ps_buffer2[(segment * 2) + 0] = ps_buffer[(segment * 2) + 0]; // Make a copy of the PS buffer
ps_buffer2[(offset * 2) + 1] = ps_buffer[(offset * 2) + 1]; ps_buffer2[(segment * 2) + 1] = ps_buffer[(segment * 2) + 1];
ps_buffer2[8] = '\0'; // Endmarker ps_buffer2[8] = '\0'; // Endmarker
ps_buffer[(offset * 2) + 0] = rds.rdsD >> 8; // First character of segment ps_buffer[(segment * 2) + 0] = rds.rdsD >> 8; // First character of segment
ps_buffer[(offset * 2) + 1] = rds.rdsD & 0xFF; // Second character of segment ps_buffer[(segment * 2) + 1] = rds.rdsD & 0xFF; // Second character of segment
ps_buffer[8] = '\0'; // Endmarker ps_buffer[8] = '\0'; // Endmarker
if (ps_process || rds.fastps == 0) { if (ps_process || rds.fastps == 0) {
if (offset == 0) { if (segment == 0) {
packet0 = true; packet0 = true;
packet1 = false; packet1 = false;
packet2 = false; packet2 = false;
packet3 = false; packet3 = false;
} }
if (offset == 1) packet1 = true; if (segment == 1) packet1 = true;
if (offset == 2) packet2 = true; if (segment == 2) packet2 = true;
if (offset == 3) packet3 = true; if (segment == 3) packet3 = true;
} }
if (packet0 && packet1 && packet2 && packet3 && (ps_process || (rds.fastps == 0 && rds.fastps != 2))) { // Last chars are received if (packet0 && packet1 && packet2 && packet3 && (ps_process || (rds.fastps == 0 && rds.fastps != 2))) { // Last chars are received
@@ -615,198 +599,186 @@ void TEF6686::readRDS(byte showrdserrors) {
} }
if ((!ps_process && rds.fastps > 0 && rds.fastps != 2) || rds.fastps == 2) { // Let's get 2 runs of 8 PS characters fast and without refresh if ((!ps_process && rds.fastps > 0 && rds.fastps != 2) || rds.fastps == 2) { // Let's get 2 runs of 8 PS characters fast and without refresh
if (offset == 0) packet0 = true; if (segment == 0) packet0 = true;
if (offset == 1) packet1 = true; if (segment == 1) packet1 = true;
if (offset == 2) packet2 = true; if (segment == 2) packet2 = true;
if (offset == 3) packet3 = true; if (segment == 3) packet3 = true;
RDScharConverter(ps_buffer, PStext, sizeof(PStext) / sizeof(wchar_t), (underscore > 0 ? true : false)); // Convert 8 bit ASCII to 16 bit ASCII RDScharConverter(ps_buffer, PStext, sizeof(PStext) / sizeof(wchar_t), (underscore > 0 ? true : false)); // Convert 8 bit ASCII to 16 bit ASCII
String utf8String = convertToUTF8(PStext); // Convert RDS characterset to ASCII String utf8String = convertToUTF8(PStext); // Convert RDS characterset to ASCII
rds.stationName = extractUTF8Substring(utf8String, 0, 8, (underscore > 0 ? true : false)); rds.stationName = extractUTF8Substring(utf8String, 0, 8, (underscore > 0 ? true : false));
if (packet0 && packet1 && packet2 && packet3) ps_process = true; // OK, we had one runs, now let's go the idle PS writing if (packet0 && packet1 && packet2 && packet3) ps_process = true; // OK, we had one runs, now let's go the idle PS writing
} }
if (offset == 0) rds.hasDynamicPTY = bitRead(rds.rdsB, 2) & 0x1F; // Dynamic PTY flag if(segment == 0) rds.hasDynamicPTY = bitRead(rds.rdsB, 2) & 0x1F;
if (offset == 1) rds.hasCompressed = bitRead(rds.rdsB, 2) & 0x1F; // Compressed flag else if(segment == 1) rds.hasCompressed = bitRead(rds.rdsB, 2) & 0x1F;
if (offset == 2) rds.hasArtificialhead = bitRead(rds.rdsB, 2) & 0x1F; // Artificial head flag else if(segment == 2) rds.hasArtificialhead = bitRead(rds.rdsB, 2) & 0x1F;
if (offset == 3) rds.hasStereo = bitRead(rds.rdsB, 2) & 0x1F; // Stereo flag else if(segment == 3) rds.hasStereo = bitRead(rds.rdsB, 2) & 0x1F;
} }
if (!rdsBerrorThreshold) { rds.hasTA = (bitRead(rds.rdsB, 4));
rds.stationTypeCode = (rds.rdsB >> 5) & 0x1F; // Get 5 PTY bits from Block B
if (rds.region == 0) strcpy(rds.stationType, PTY_EU[rds.stationTypeCode]); else strcpy(rds.stationType, PTY_USA[rds.stationTypeCode]);
rds.hasTA = (bitRead(rds.rdsB, 4)); // Read TA flag if (!rdsCerrorThreshold && rdsgroup == RDS_GROUP_0A && rds.rdsC != rdsCold) {
}
rds.hasTP = (bitRead(rds.rdsB, 10)); // Read TP flag
if (!rdsCerrorThreshold) {
//AF decoder //AF decoder
if (rdsblock == 0 && rds.rdsC != rdsCold) { // Only when in GROUP 0A if ((rds.rdsC >> 8) > 224 && (rds.rdsC >> 8) < 250) {
afinit = true; // AF detected
if ((rds.rdsC >> 8) > 224 && (rds.rdsC >> 8) < 250) { rds.hasAF = true;
afinit = true; // AF detected
rds.hasAF = true;
}
if (afinit) {
if ((rds.rdsC >> 8) > 224 && (rds.rdsC >> 8) < 250 && ((rds.rdsC & 0xFF) * 10 + 8750) == currentfreq && rds.hasAF) {
if (afmethodBtrigger) afmethodB = true; // Check for AF method B
afmethodBprobe = true;
af_counterb = (rds.rdsC >> 8) - 224;
af_number = (rds.rdsC >> 8) - 224;
af_counterbcheck = 1;
doublecounter = 0;
doubletestfreq = (rds.rdsC & 0xFF) * 10 + 8750;
} else if ((rds.rdsC >> 8) > 224 && (rds.rdsC >> 8) < 250 && ((rds.rdsC & 0xFF) * 10 + 8750) != currentfreq && rds.hasAF) {
afmethodBprobe = false;
afmethodBtrigger = true;
af_counterb = 0;
af_number = (rds.rdsC >> 8) - 224;
af_counterbcheck = 0;
doublecounter = 0;
doubletestfreq = (rds.rdsC & 0xFF) * 10 + 8750;
}
if (((rds.rdsC >> 8) > 0 && (rds.rdsC >> 8) < 205) && ((rds.rdsC >> 8) > 0 && (rds.rdsC >> 8) < 205)) {
if (afmethodBprobe) af_counterbcheck += 2;
}
if ((rds.rdsB >> 11) == 0 && af_counter < 50) {
uint16_t buffer0;
uint16_t buffer1;
if ((rds.rdsC >> 8) > 0 && (rds.rdsC >> 8) < 205) buffer0 = (rds.rdsC >> 8) * 10 + 8750; else buffer0 = 0;
if ((rds.rdsC & 0xFF) > 0 && (rds.rdsC & 0xFF) < 205) buffer1 = (rds.rdsC & 0xFF) * 10 + 8750; else buffer1 = 0;
if (((rds.rdsC >> 8) > 0 && (rds.rdsC >> 8) < 205) && (buffer0 == doubletestfreq || buffer1 == doubletestfreq)) doublecounter++;
if (doublecounter > (af_number / 2)) afmethodB = true; // If signed frequency also appears more than once in the AF list, AF Method B detected
if (afmethodBprobe && af_counterbcheck > af_counterb) afmethodBprobe = false; // If more than counter received disable probe flag
if (afmethodBprobe) { // Check for Reg. flags
if (buffer1 == currentfreq && buffer0 > buffer1) {
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer0 && !af[x].regional) {
af[x].regional = true;
af_updatecounter++;
break;
}
}
} else if (buffer1 == currentfreq && buffer0 < buffer1) {
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer0 && !af[x].same) {
af[x].same = true;
af_updatecounter++;
break;
}
}
}
if (buffer0 == currentfreq && buffer0 > buffer1) {
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer1 && !af[x].regional) {
af[x].regional = true;
af_updatecounter++;
break;
}
}
} else if (buffer0 == currentfreq && buffer0 < buffer1) {
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer1 && !af[x].same) {
af[x].same = true;
af_updatecounter++;
break;
}
}
}
}
if (buffer0 != currentfreq && buffer1 != currentfreq && afmethodB && afmethodBprobe) {
afmethodBprobe = false; // Remove faulty Reg. flags
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer0 || af[x].frequency == buffer1) {
if (af[x].same) {
af[x].same = false;
af_updatecounter++;
}
if (af[x].regional) {
af[x].regional = false;
af_updatecounter++;
}
}
break;
}
}
bool isValuePresent = false;
for (int i = 0; i < 50; i++) { // Check if already in list
if ((rds.sortaf && (buffer0 == currentfreq)) || buffer0 == 0 || af[i].frequency == buffer0) {
isValuePresent = true;
break;
}
}
if (!isValuePresent) { // Add frequency to list
af[af_counter].frequency = buffer0;
if (af_counter < 50) af_counter++;
af_updatecounter++;
}
isValuePresent = false;
for (int i = 0; i < 50; i++) { // Check if already in list
if ((rds.sortaf && (buffer1 == currentfreq)) || buffer1 == 0 || af[i].frequency == buffer1) {
isValuePresent = true;
break;
}
}
if (!isValuePresent) {
af[af_counter].frequency = buffer1; // Add frequency to list
if (af_counter < 50) af_counter++;
af_updatecounter++;
}
if (rds.sortaf) { // Sort AF list (low to high)
for (int i = 0; i < 50; i++) {
for (int j = 0; j < 50 - i; j++) {
if (af[j].frequency == 0) continue;
if (af[j].frequency > af[j + 1].frequency && af[j + 1].frequency != 0) {
uint16_t temp = af[j].frequency;
bool temp3 = af[j].afvalid;
bool temp4 = af[j].checked;
bool temp5 = af[j].regional;
bool temp6 = af[j].same;
af[j].frequency = af[j + 1].frequency;
af[j].afvalid = af[j + 1].afvalid;
af[j].checked = af[j + 1].checked;
af[j].regional = af[j + 1].regional;
af[j].same = af[j + 1].same;
af[j + 1].frequency = temp;
af[j + 1].afvalid = temp3;
af[j + 1].checked = temp4;
af[j + 1].regional = temp5;
af[j + 1].same = temp6;
}
}
}
}
}
}
rdsCold = rds.rdsC;
} }
if (afinit) {
if ((rds.rdsC >> 8) > 224 && (rds.rdsC >> 8) < 250 && ((rds.rdsC & 0xFF) * 10 + 8750) == currentfreq && rds.hasAF) {
if (afmethodBtrigger) afmethodB = true;
afmethodBprobe = true;
af_counterb = (rds.rdsC >> 8) - 224;
af_number = (rds.rdsC >> 8) - 224;
af_counterbcheck = 1;
doublecounter = 0;
doubletestfreq = (rds.rdsC & 0xFF) * 10 + 8750;
} else if ((rds.rdsC >> 8) > 224 && (rds.rdsC >> 8) < 250 && ((rds.rdsC & 0xFF) * 10 + 8750) != currentfreq && rds.hasAF) {
afmethodBprobe = false;
afmethodBtrigger = true;
af_counterb = 0;
af_number = (rds.rdsC >> 8) - 224;
af_counterbcheck = 0;
doublecounter = 0;
doubletestfreq = (rds.rdsC & 0xFF) * 10 + 8750;
}
if (((rds.rdsC >> 8) > 0 && (rds.rdsC >> 8) < 205) && ((rds.rdsC >> 8) > 0 && (rds.rdsC >> 8) < 205)) {
if (afmethodBprobe) af_counterbcheck += 2;
}
if ((rds.rdsB >> 11) == 0 && af_counter < 50) {
uint16_t buffer0;
uint16_t buffer1;
if ((rds.rdsC >> 8) > 0 && (rds.rdsC >> 8) < 205) buffer0 = (rds.rdsC >> 8) * 10 + 8750; else buffer0 = 0;
if ((rds.rdsC & 0xFF) > 0 && (rds.rdsC & 0xFF) < 205) buffer1 = (rds.rdsC & 0xFF) * 10 + 8750; else buffer1 = 0;
if (((rds.rdsC >> 8) > 0 && (rds.rdsC >> 8) < 205) && (buffer0 == doubletestfreq || buffer1 == doubletestfreq)) doublecounter++;
if (doublecounter > (af_number / 2)) afmethodB = true; // If signed frequency also appears more than once in the AF list, AF Method B detected
if (afmethodBprobe && af_counterbcheck > af_counterb) afmethodBprobe = false; // If more than counter received disable probe flag
if (afmethodBprobe) { // Check for Reg. flags
if (buffer1 == currentfreq && buffer0 > buffer1) {
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer0 && !af[x].regional) {
af[x].regional = true;
af_updatecounter++;
break;
}
}
} else if (buffer1 == currentfreq && buffer0 < buffer1) {
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer0 && !af[x].same) {
af[x].same = true;
af_updatecounter++;
break;
}
}
}
if (buffer0 == currentfreq && buffer0 > buffer1) {
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer1 && !af[x].regional) {
af[x].regional = true;
af_updatecounter++;
break;
}
}
} else if (buffer0 == currentfreq && buffer0 < buffer1) {
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer1 && !af[x].same) {
af[x].same = true;
af_updatecounter++;
break;
}
}
}
}
if (buffer0 != currentfreq && buffer1 != currentfreq && afmethodB && afmethodBprobe) {
afmethodBprobe = false; // Remove faulty Reg. flags
for (int x = 0; x < af_counter; x++) {
if (af[x].frequency == buffer0 || af[x].frequency == buffer1) {
if (af[x].same) {
af[x].same = false;
af_updatecounter++;
}
if (af[x].regional) {
af[x].regional = false;
af_updatecounter++;
}
}
break;
}
}
bool isValuePresent = false;
for (int i = 0; i < 50; i++) { // Check if already in list
if ((rds.sortaf && (buffer0 == currentfreq)) || buffer0 == 0 || af[i].frequency == buffer0) {
isValuePresent = true;
break;
}
}
if (!isValuePresent) { // Add frequency to list
af[af_counter].frequency = buffer0;
if (af_counter < 50) af_counter++;
af_updatecounter++;
}
isValuePresent = false;
for (int i = 0; i < 50; i++) { // Check if already in list
if ((rds.sortaf && (buffer1 == currentfreq)) || buffer1 == 0 || af[i].frequency == buffer1) {
isValuePresent = true;
break;
}
}
if (!isValuePresent) {
af[af_counter].frequency = buffer1; // Add frequency to list
if (af_counter < 50) af_counter++;
af_updatecounter++;
}
if (rds.sortaf) { // Sort AF list (low to high)
for (int i = 0; i < 50; i++) {
for (int j = 0; j < 50 - i; j++) {
if (af[j].frequency == 0) continue;
if (af[j].frequency > af[j + 1].frequency && af[j + 1].frequency != 0) {
uint16_t temp = af[j].frequency;
bool temp3 = af[j].afvalid;
bool temp4 = af[j].checked;
bool temp5 = af[j].regional;
bool temp6 = af[j].same;
af[j].frequency = af[j + 1].frequency;
af[j].afvalid = af[j + 1].afvalid;
af[j].checked = af[j + 1].checked;
af[j].regional = af[j + 1].regional;
af[j].same = af[j + 1].same;
af[j + 1].frequency = temp;
af[j + 1].afvalid = temp3;
af[j + 1].checked = temp4;
af[j + 1].regional = temp5;
af[j + 1].same = temp6;
}
}
}
}
}
}
rdsCold = rds.rdsC;
} }
} break; } break;
case RDS_GROUP_1A: case RDS_GROUP_1A: {
case RDS_GROUP_1B: { if (!rdsCerrorThreshold && ((rds.rdsC >> 12) & 0x07) == 0) {
if (!rdsCerrorThreshold) { rds.ECC = rds.rdsC & 0xff;
if (((rds.rdsC >> 12) & 0x07) == 0 && rdsblock == RDS_GROUP_1A) { // ECC code readout rds.hasECC = true;
rds.ECC = rds.rdsC & 0xff;
rds.hasECC = true;
switch (rds.picode[0]) { switch (rds.picode[0]) {
case '1': { case '1': {
if (rds.ECC == 160) rds.ECCtext = ECCtext[226]; if (rds.ECC == 160) rds.ECCtext = ECCtext[226];
if (rds.ECC == 162) rds.ECCtext = ECCtext[129]; if (rds.ECC == 162) rds.ECCtext = ECCtext[129];
@@ -1114,17 +1086,13 @@ void TEF6686::readRDS(byte showrdserrors) {
break; break;
} }
} }
}
} }
} break;
if (rds.rdsC >> 12 == 1 && rdsblock == RDS_GROUP_1A) rds.hasTMC = true; // TMC flag
} break;
case RDS_GROUP_2A: { case RDS_GROUP_2A: {
if (showrdserrors == 3 || (!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold)) { if (showrdserrors == 3 || !(rdsCerrorThreshold && rdsDerrorThreshold)) {
// RT decoder (64 characters)
rds.hasRT = true; rds.hasRT = true;
rds.rtAB = (bitRead(rds.rdsB, 4)); // Get AB flag rds.rtAB = (bitRead(rds.rdsB, 4));
if (initab) { if (initab) {
rtABold = rds.rtAB; rtABold = rds.rtAB;
@@ -1139,19 +1107,16 @@ void TEF6686::readRDS(byte showrdserrors) {
} }
} }
if (rds.rtAB != rtABold) { // Erase old RT, because of AB change if (rds.rtAB != rtABold) {
initrt = false; initrt = false;
if (rds.rtbuffer) { if (rds.rtbuffer) {
char rt_buffer_temp[129]; char rt_buffer_temp[129];
bool found = false;
strcpy(rt_buffer_temp, rt_buffer); strcpy(rt_buffer_temp, rt_buffer);
for (int i = 0; i < 129; i++) { for (int i = 0; i < 129; i++) {
if (rt_buffer_temp[i] == 0x0D) { if (rt_buffer_temp[i] == '\r') {
found = true;
}
if (found) {
rt_buffer_temp[i] = '\0'; rt_buffer_temp[i] = '\0';
break;
} }
} }
@@ -1162,31 +1127,25 @@ void TEF6686::readRDS(byte showrdserrors) {
rds.stationText = trimTrailingSpaces(rds.stationText); // Trim empty spaces at the end rds.stationText = trimTrailingSpaces(rds.stationText); // Trim empty spaces at the end
} }
for (byte i = 0; i < 64; i++) { for (byte i = 0; i < 64; i++) rt_buffer[i] = 0x20;
rt_buffer[i] = 0x20;
}
rt_buffer[64] = '\0'; rt_buffer[64] = '\0';
rtABold = rds.rtAB; rtABold = rds.rtAB;
} }
offset = (rds.rdsB & 0xf) * 4; // Get RT character segment uint8_t segment = (rds.rdsB & 0xf) * 4;
rt_buffer[offset + 0] = rds.rdsC >> 8; // First character of segment rt_buffer[segment + 0] = rds.rdsC >> 8;
rt_buffer[offset + 1] = rds.rdsC & 0xff; // Second character of segment rt_buffer[segment + 1] = rds.rdsC & 0xff;
rt_buffer[offset + 2] = rds.rdsD >> 8; // Thirth character of segment rt_buffer[segment + 2] = rds.rdsD >> 8;
rt_buffer[offset + 3] = rds.rdsD & 0xff; // Fourth character of segment rt_buffer[segment + 3] = rds.rdsD & 0xff;
if (initrt || !rds.rtbuffer) { if (initrt || !rds.rtbuffer) {
char rt_buffer_temp[129]; char rt_buffer_temp[129];
bool found = false;
strcpy(rt_buffer_temp, rt_buffer); strcpy(rt_buffer_temp, rt_buffer);
for (int i = 0; i < 129; i++) { for (int i = 0; i < 129; i++) {
if (rt_buffer_temp[i] == 0x0D) { if (rt_buffer_temp[i] == '\r') {
found = true;
}
if (found) {
rt_buffer_temp[i] = '\0'; rt_buffer_temp[i] = '\0';
break;
} }
} }
@@ -1199,7 +1158,7 @@ void TEF6686::readRDS(byte showrdserrors) {
for (int i = 0; i < 64; i++) rt_buffer2[i] = rt_buffer[i]; for (int i = 0; i < 64; i++) rt_buffer2[i] = rt_buffer[i];
} }
} break; } break;
case RDS_GROUP_2B: { case RDS_GROUP_2B: {
if (showrdserrors == 3 || (!rdsBerrorThreshold && !rdsDerrorThreshold)) { if (showrdserrors == 3 || (!rdsBerrorThreshold && !rdsDerrorThreshold)) {
@@ -1215,9 +1174,9 @@ void TEF6686::readRDS(byte showrdserrors) {
rtAB32old = rds.rtAB32; rtAB32old = rds.rtAB32;
} }
offset = (rds.rdsB & 0xf) * 2; // Get RT character segment uint16_t segment = (rds.rdsB & 0xf) * 2; // Get RT character segment
rt_buffer32[offset + 0] = rds.rdsD >> 8; // First character of segment rt_buffer32[segment + 0] = rds.rdsD >> 8; // First character of segment
rt_buffer32[offset + 1] = rds.rdsD & 0xff; // Second character of segment rt_buffer32[segment + 1] = rds.rdsD & 0xff; // Second character of segment
byte endmarkerRT32 = 32; byte endmarkerRT32 = 32;
for (byte i = 0; i < endmarkerRT32; i++) { for (byte i = 0; i < endmarkerRT32; i++) {
@@ -1229,15 +1188,12 @@ void TEF6686::readRDS(byte showrdserrors) {
char rt_buffer_temp[129]; char rt_buffer_temp[129];
bool found = false;
strcpy(rt_buffer_temp, rt_buffer32); strcpy(rt_buffer_temp, rt_buffer32);
for (int i = 0; i < 129; i++) { for (int i = 0; i < 129; i++) {
if (rt_buffer_temp[i] == 0x0D) { if (rt_buffer_temp[i] == '\r') {
found = true;
}
if (found) {
rt_buffer_temp[i] = '\0'; rt_buffer_temp[i] = '\0';
break;
} }
} }
@@ -1266,25 +1222,22 @@ void TEF6686::readRDS(byte showrdserrors) {
rds.aid_counter++; rds.aid_counter++;
} }
if (rds.rdsD == 0xCD46) { // Check for TMC application if (rds.rdsD == 0xCD46) rds.hasTMC = true;
rds.hasTMC = true; // TMC flag
if (rds.rdsD == 0x4BD7) {
rds.hasRTplus = true;
rtplusblock = ((rds.rdsB & 0x1F) >> 1) * 2;
} }
// RT+ init if (rds.rdsD == 0x0093) {
if (rds.rdsD == 0x4BD7) { // Check for RT+ application rds.hasDABAF = true;
rds.hasRDSplus = true; // Set flag DABAFblock = ((rds.rdsB & 0x1F) >> 1) * 2;
rtplusblock = ((rds.rdsB & 0x1F) >> 1) * 2; // Get RT+ Block
} }
if (rds.rdsD == 0x0093) { // Check for DAB+ AF application if (rds.rdsD == 0x6552) {
rds.hasDABAF = true; // Set flag _hasEnhancedRT = true;
DABAFblock = ((rds.rdsB & 0x1F) >> 1) * 2; // Get DAB AF Block eRTblock = ((rds.rdsB & 0x1F) >> 1) * 2;
} eRTcoding = bitRead(rds.rdsC, 0);
if (rds.rdsD == 0x6552) { // Check for Enhanced RT application
_hasEnhancedRT = true; // Set flag
eRTblock = ((rds.rdsB & 0x1F) >> 1) * 2; // Get eRT block
eRTcoding = bitRead(rds.rdsC, 0); // 0 = UCS-2, 1 = UTF-8
} }
} }
} break; } break;
@@ -1292,11 +1245,8 @@ void TEF6686::readRDS(byte showrdserrors) {
case RDS_GROUP_4A: { case RDS_GROUP_4A: {
if (!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold && rds.ctupdate && (rds.PICTlock == rds.rdsA || rds.PICTlock == 0)) { if (!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold && rds.ctupdate && (rds.PICTlock == rds.rdsA || rds.PICTlock == 0)) {
// CT // CT
uint32_t mjd; uint32_t mjd = (rds.rdsB & 0x03) << 15 | ((rds.rdsC >> 1) & 0x7FFF);;
mjd = (rds.rdsB & 0x03); uint16_t hour, minute, day = 5, month = 1, year = 2026;
mjd <<= 15;
mjd += ((rds.rdsC >> 1) & 0x7FFF);
uint16_t hour, minute, day = 1, month = 1, year = 2020; // Set default values for day, month, and year
int32_t timeoffset; int32_t timeoffset;
long J, C, Y, M; long J, C, Y, M;
@@ -1313,14 +1263,13 @@ void TEF6686::readRDS(byte showrdserrors) {
if ((M + 2 - (12 * J)) < 13) month = M + 2 - (12 * J); if ((M + 2 - (12 * J)) < 13) month = M + 2 - (12 * J);
if ((100 * (C - 49) + Y + J) > 2022) year = 100 * (C - 49) + Y + J; if ((100 * (C - 49) + Y + J) > 2022) year = 100 * (C - 49) + Y + J;
hour = ((rds.rdsD >> 12) & 0x000f); hour = ((rds.rdsD >> 12) & 0xf) | ((rds.rdsC << 4) & 0x10);
hour += ((rds.rdsC << 4) & 0x0010);
timeoffset = rds.rdsD & 0x001f; timeoffset = rds.rdsD & 0x001f;
if (bitRead(rds.rdsD, 5)) timeoffset *= -1; if (bitRead(rds.rdsD, 5)) timeoffset *= -1;
timeoffset *= 1800; timeoffset *= 1800;
minute = (rds.rdsD & 0x0fc0) >> 6; minute = (rds.rdsD & 0x0fc0) >> 6;
if (year < 2024 || hour > 23 || minute > 59 || timeoffset > 55800 || timeoffset < -55800) break; if (year < 2026 || hour > 23 || minute > 59 || timeoffset > 55800 || timeoffset < -55800) break;
struct tm tm; struct tm tm;
tm.tm_year = year - 1900; tm.tm_year = year - 1900;
@@ -1340,9 +1289,7 @@ void TEF6686::readRDS(byte showrdserrors) {
rds.hasCT = true; rds.hasCT = true;
rds.time = rdstime; rds.time = rdstime;
rds.offset = timeoffset; rds.offset = timeoffset;
} else { } else rds.hasCT = false;
rds.hasCT = false;
}
lastrdstime = rdstime; lastrdstime = rdstime;
lasttimeoffset = timeoffset; lasttimeoffset = timeoffset;
} }
@@ -1351,16 +1298,16 @@ void TEF6686::readRDS(byte showrdserrors) {
case RDS_GROUP_10A: { case RDS_GROUP_10A: {
if (!rdsCerrorThreshold && !rdsDerrorThreshold) { if (!rdsCerrorThreshold && !rdsDerrorThreshold) {
// PTYN // PTYN
offset = bitRead(rds.rdsB, 0); // Get char offset uint8_t segment = bitRead(rds.rdsB, 0);
if (rds.rdsC != 0 && rds.rdsD != 0) { if (rds.rdsC != 0 && rds.rdsD != 0) {
ptyn_buffer[(offset * 4) + 0] = rds.rdsC >> 8; // Get position 1 and 5 ptyn_buffer[(segment * 4) + 0] = rds.rdsC >> 8;
ptyn_buffer[(offset * 4) + 1] = rds.rdsC & 0xFF; // Get position 2 and 6 ptyn_buffer[(segment * 4) + 1] = rds.rdsC & 0xFF;
ptyn_buffer[(offset * 4) + 2] = rds.rdsD >> 8; // Get position 3 and 7 ptyn_buffer[(segment * 4) + 2] = rds.rdsD >> 8;
ptyn_buffer[(offset * 4) + 3] = rds.rdsD & 0xFF; // Get position 4 and 8 ptyn_buffer[(segment * 4) + 3] = rds.rdsD & 0xFF;
for (byte i = 0; i < 8; i++) PTYNtext[i] = L'\0'; for (byte i = 0; i < 8; i++) PTYNtext[i] = L'\0';
RDScharConverter(ptyn_buffer, PTYNtext, sizeof(PTYNtext) / sizeof(wchar_t), false); // Convert 8 bit ASCII to 16 bit ASCII RDScharConverter(ptyn_buffer, PTYNtext, sizeof(PTYNtext) / sizeof(wchar_t), false);
String utf8String = convertToUTF8(PTYNtext); // Convert RDS characterset to ASCII String utf8String = convertToUTF8(PTYNtext);
rds.PTYN = extractUTF8Substring(utf8String, 0, 8, false); // Make sure text is not longer than 8 chars rds.PTYN = extractUTF8Substring(utf8String, 0, 8, false);
rds.hasPTYN = true; rds.hasPTYN = true;
} }
} }
@@ -1373,9 +1320,9 @@ void TEF6686::readRDS(byte showrdserrors) {
case RDS_GROUP_9A: case RDS_GROUP_9A:
case RDS_GROUP_11A: case RDS_GROUP_11A:
case RDS_GROUP_12A: case RDS_GROUP_12A:
case RDS_GROUP_13A: { case RDS_GROUP_13A: {
// RT+ decoding // RT+ decoding
if ((!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) && rtplusblock == rdsblock && rds.hasRDSplus) { if ((!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) && rtplusblock == rdsgroup && rds.hasRTplus) {
rds.rdsplusTag1 = ((rds.rdsB & 0x07) << 3) + (rds.rdsC >> 13); // Are we in the right RT+ block and is all ok to go? rds.rdsplusTag1 = ((rds.rdsB & 0x07) << 3) + (rds.rdsC >> 13); // Are we in the right RT+ block and is all ok to go?
rds.rdsplusTag2 = ((rds.rdsC & 0x01) << 5) + (rds.rdsD >> 11); rds.rdsplusTag2 = ((rds.rdsC & 0x01) << 5) + (rds.rdsD >> 11);
uint16_t start_marker_1 = (rds.rdsC >> 7) & 0x3F; uint16_t start_marker_1 = (rds.rdsC >> 7) & 0x3F;
@@ -1428,8 +1375,8 @@ void TEF6686::readRDS(byte showrdserrors) {
} }
// eRT decoding // eRT decoding
if ((!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) && eRTblock == rdsblock && _hasEnhancedRT) { if ((!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) && eRTblock == rdsgroup && _hasEnhancedRT) {
offset = (rds.rdsB & 0x1f) * 4; uint8_t offset = (rds.rdsB & 0x1f) * 4;
eRT_buffer[offset + 0] = rds.rdsC >> 8; // First character of segment eRT_buffer[offset + 0] = rds.rdsC >> 8; // First character of segment
eRT_buffer[offset + 1] = rds.rdsC & 0xff; // Second character of segment eRT_buffer[offset + 1] = rds.rdsC & 0xff; // Second character of segment
eRT_buffer[offset + 2] = rds.rdsD >> 8; // Thirth character of segment eRT_buffer[offset + 2] = rds.rdsD >> 8; // Thirth character of segment
@@ -1454,9 +1401,9 @@ void TEF6686::readRDS(byte showrdserrors) {
} }
if (!rdsBerrorThreshold && rdsblock == 16 && (bitRead(rds.rdsB, 15))) rds.hasTMC = true; // TMC flag if (!rdsBerrorThreshold && rdsgroup == 16 && (bitRead(rds.rdsB, 15))) rds.hasTMC = true; // TMC flag
if ((!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) && DABAFblock == rdsblock && rds.hasDABAF) { if ((!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) && DABAFblock == rdsgroup && rds.hasDABAF) {
rds.dabaffreq = (rds.rdsC * 16); rds.dabaffreq = (rds.rdsC * 16);
for (size_t i = 0; i < sizeof(DABfrequencyTable) / sizeof(DABfrequencyTable[0]); ++i) { for (size_t i = 0; i < sizeof(DABfrequencyTable) / sizeof(DABfrequencyTable[0]); ++i) {
@@ -1468,11 +1415,8 @@ void TEF6686::readRDS(byte showrdserrors) {
rds.dabafeid[2] = (rds.rdsD >> 4) & 0xF; rds.dabafeid[2] = (rds.rdsD >> 4) & 0xF;
rds.dabafeid[3] = rds.rdsD & 0xF; rds.dabafeid[3] = rds.rdsD & 0xF;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (rds.dabafeid[i] < 10) { if (rds.dabafeid[i] < 10) rds.dabafeid[i] += '0';
rds.dabafeid[i] += '0'; // Add ASCII offset for decimal digits else rds.dabafeid[i] += 'A' - 10;
} else {
rds.dabafeid[i] += 'A' - 10; // Add ASCII offset for hexadecimal letters A-F
}
} }
rds.dabafeid[4] = 0; rds.dabafeid[4] = 0;
} }
@@ -1501,21 +1445,16 @@ void TEF6686::readRDS(byte showrdserrors) {
eon[eon_counter].picode[2] = (rds.rdsD >> 4) & 0xF; eon[eon_counter].picode[2] = (rds.rdsD >> 4) & 0xF;
eon[eon_counter].picode[3] = rds.rdsD & 0xF; eon[eon_counter].picode[3] = rds.rdsD & 0xF;
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
if (eon[eon_counter].picode[j] < 10) { if (eon[eon_counter].picode[j] < 10) eon[eon_counter].picode[j] += '0';
eon[eon_counter].picode[j] += '0'; // Add ASCII offset for decimal digits else eon[eon_counter].picode[j] += 'A' - 10;
} else {
eon[eon_counter].picode[j] += 'A' - 10; // Add ASCII offset for hexadecimal letters A-F
}
} }
eon[eon_counter].pi = rds.rdsD; // Store PI on next array eon[eon_counter].pi = rds.rdsD; // Store PI on next array
if (eon_counter < 20) eon_counter++; if (eon_counter < 20) eon_counter++;
eonIndex = eon_counter - 1; eonIndex = eon_counter - 1;
} else { } else eonIndex = i;
eonIndex = i;
}
offset = rds.rdsB & 0x0F; // Read offset uint8_t offset = rds.rdsB & 0x0F; // Read offset
if (offset < 4 && eon[eonIndex].pi == rds.rdsD) { if (offset < 4 && eon[eonIndex].pi == rds.rdsD) {
eon_buffer[eonIndex][(offset * 2) + 0] = rds.rdsC >> 8; // First character of segment eon_buffer[eonIndex][(offset * 2) + 0] = rds.rdsC >> 8; // First character of segment
@@ -1583,7 +1522,7 @@ void TEF6686::readRDS(byte showrdserrors) {
case RDS_GROUP_15A: { case RDS_GROUP_15A: {
if (showrdserrors == 3 || (!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold)) { if (showrdserrors == 3 || (!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold)) {
if (pslong_process && rds.stationNameLong.length() > 0) rds.hasLongPS = true; if (pslong_process && rds.stationNameLong.length() > 0) rds.hasLongPS = true;
offset = (rds.rdsB & 0xf) * 4; // Get Long PS character segment uint8_t offset = (rds.rdsB & 0xf) * 4; // Get Long PS character segment
pslong_buffer2[offset + 0] = pslong_buffer[offset + 0]; // Copy PS long buffer pslong_buffer2[offset + 0] = pslong_buffer[offset + 0]; // Copy PS long buffer
pslong_buffer2[offset + 1] = pslong_buffer[offset + 1]; pslong_buffer2[offset + 1] = pslong_buffer[offset + 1];
@@ -1630,6 +1569,7 @@ void TEF6686::readRDS(byte showrdserrors) {
} }
break; break;
} }
end:
previous_rdsA = rds.rdsA; previous_rdsA = rds.rdsA;
previous_rdsB = rds.rdsB; previous_rdsB = rds.rdsB;
previous_rdsC = rds.rdsC; previous_rdsC = rds.rdsC;
@@ -1737,17 +1677,17 @@ void TEF6686::clearRDS(bool fullsearchrds) {
for (i = 0; i < 10; i++) rds.aid[i] = 0; for (i = 0; i < 10; i++) rds.aid[i] = 0;
rdsblock = 254; rdsgroup = 254;
processed_rdsblocks = 0; processed_rdsblocks = 0;
piold = 0; piold = 0;
rds.correctPI = 0; rds.correctPI = 0;
rds.ECC = 254; rds.ECC = 254;
rds.stationTypeCode = 32; rds.PTY = 32;
rds.dabaffreq = 0; rds.dabaffreq = 0;
rds.hasECC = false; rds.hasECC = false;
rds.hasRT = false; rds.hasRT = false;
rds.hasRDS = false; rds.hasRDS = false;
rds.hasTP = false; rds.TP = false;
rds.hasAF = false; rds.hasAF = false;
rds.hasTA = false; rds.hasTA = false;
rds.hasEON = false; rds.hasEON = false;
@@ -1756,7 +1696,7 @@ void TEF6686::clearRDS(bool fullsearchrds) {
rds.hasAID = false; rds.hasAID = false;
rds.hasPTYN = false; rds.hasPTYN = false;
rds.hasLongPS = false; rds.hasLongPS = false;
rds.hasRDSplus = false; rds.hasRTplus = false;
rds.hasDABAF = false; rds.hasDABAF = false;
rds.hasEnhancedRT = false; rds.hasEnhancedRT = false;
rt_process = false; rt_process = false;
@@ -2040,6 +1980,7 @@ String TEF6686::ucs2ToUtf8(const char* ucs2Input) {
return utf8Output; return utf8Output;
} }
static const char* fixedCalls[] = {"CBLA", "CBFM", "CBOT"};
bool TEF6686::isFixedCallsign(uint16_t stationID, char* stationIDStr) { bool TEF6686::isFixedCallsign(uint16_t stationID, char* stationIDStr) {
for (int i = 0; i < sizeof(fixedPI) / sizeof(fixedPI[0]); i++) { for (int i = 0; i < sizeof(fixedPI) / sizeof(fixedPI[0]); i++) {
if (stationID == fixedPI[i]) { if (stationID == fixedPI[i]) {
+6 -5
View File
@@ -1296,7 +1296,7 @@ void ShowOneLine(byte position, byte item, bool selected) {
FullLineSprite.setTextDatum(TR_DATUM); FullLineSprite.setTextDatum(TR_DATUM);
FullLineSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); FullLineSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false);
switch (scancancel) { switch (scancancel) {
case OFF: FullLineSprite.drawString(textUI(30), 298, 2); break; case SCAN_CANCEL: FullLineSprite.drawString(textUI(30), 298, 2); break;
case CORRECTPI: FullLineSprite.drawString(textUI(220), 298, 2); break; case CORRECTPI: FullLineSprite.drawString(textUI(220), 298, 2); break;
case SIGNAL: FullLineSprite.drawString(textUI(221), 298, 2); break; case SIGNAL: FullLineSprite.drawString(textUI(221), 298, 2); break;
} }
@@ -2408,7 +2408,7 @@ void ShowOneButton(byte position, byte item, bool selected) {
PSSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); PSSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false);
switch (scancancel) { switch (scancancel) {
case OFF: PSSprite.drawString(textUI(30), 75, 15); break; case 0: PSSprite.drawString(textUI(30), 75, 15); break;
case CORRECTPI: PSSprite.drawString(textUI(220), 75, 15); break; case CORRECTPI: PSSprite.drawString(textUI(220), 75, 15); break;
case SIGNAL: PSSprite.drawString(textUI(221), 75, 15); break; case SIGNAL: PSSprite.drawString(textUI(221), 75, 15); break;
} }
@@ -4375,7 +4375,7 @@ void MenuUpDown(bool dir) {
} }
switch (scancancel) { switch (scancancel) {
case OFF: OneBigLineSprite.drawString(textUI(30), 135, 0); break; case SCAN_CANCEL: OneBigLineSprite.drawString(textUI(30), 135, 0); break;
case CORRECTPI: OneBigLineSprite.drawString(textUI(220), 135, 0); break; case CORRECTPI: OneBigLineSprite.drawString(textUI(220), 135, 0); break;
case SIGNAL: OneBigLineSprite.drawString(textUI(221), 135, 0); break; case SIGNAL: OneBigLineSprite.drawString(textUI(221), 135, 0); break;
} }
@@ -4657,7 +4657,8 @@ void DoMenu() {
tftPrint(ARIGHT, "marsel90-1", 145, 185, PrimaryColor, PrimaryColorSmooth, 16); tftPrint(ARIGHT, "marsel90-1", 145, 185, PrimaryColor, PrimaryColorSmooth, 16);
tftPrint(ALEFT, "lawendel", 155, 185, PrimaryColor, PrimaryColorSmooth, 16); tftPrint(ALEFT, "lawendel", 155, 185, PrimaryColor, PrimaryColorSmooth, 16);
tftPrint(ARIGHT, "KB8U", 145, 200, PrimaryColor, PrimaryColorSmooth, 16); tftPrint(ARIGHT, "KB8U", 145, 200, PrimaryColor, PrimaryColorSmooth, 16);
tftPrint(ACENTER, "github.com/PE5PVB/TEF6686_ESP32", 155, 215, ActiveColor, ActiveColorSmooth, 16); tftPrint(ALEFT, "KubaPro010", 155, 200, PrimaryColor, PrimaryColorSmooth, 16);
tftPrint(ACENTER, "github.com/KubaPro010/TEF6686_ESP32", 155, 215, ActiveColor, ActiveColorSmooth, 16);
if (hardwaremodel == PORTABLE_TOUCH_ILI9341) { if (hardwaremodel == PORTABLE_TOUCH_ILI9341) {
tft.fillRoundRect(240, 36, 60, 40, 6, FrameColor); tft.fillRoundRect(240, 36, 60, 40, 6, FrameColor);
tft.drawRoundRect(240, 36, 60, 40, 6, ActiveColor); tft.drawRoundRect(240, 36, 60, 40, 6, ActiveColor);
@@ -5470,7 +5471,7 @@ void DoMenu() {
Infoboxprint(textUI(219)); Infoboxprint(textUI(219));
switch (scancancel) { switch (scancancel) {
case OFF: OneBigLineSprite.drawString(textUI(30), 135, 0); break; case SCAN_CANCEL: OneBigLineSprite.drawString(textUI(30), 135, 0); break;
case CORRECTPI: OneBigLineSprite.drawString(textUI(220), 135, 0); break; case CORRECTPI: OneBigLineSprite.drawString(textUI(220), 135, 0); break;
case SIGNAL: OneBigLineSprite.drawString(textUI(221), 135, 0); break; case SIGNAL: OneBigLineSprite.drawString(textUI(221), 135, 0); break;
} }
+49 -162
View File
@@ -15,7 +15,6 @@ void handleRoot() {
html += "<meta charset=\"UTF-8\">"; html += "<meta charset=\"UTF-8\">";
html += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"; html += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">";
// Add CSS styling
html += "<style>"; html += "<style>";
html += "body {background-color: rgb(32, 34, 40); color: white; font-family: 'Arial', sans-serif;}"; html += "body {background-color: rgb(32, 34, 40); color: white; font-family: 'Arial', sans-serif;}";
html += "h1 {text-align: center; margin-top: 20px;font-size: 32px;}"; html += "h1 {text-align: center; margin-top: 20px;font-size: 32px;}";
@@ -39,7 +38,6 @@ void handleRoot() {
html += "</style>"; html += "</style>";
html += "</head><body>"; html += "</head><body>";
// Add logo as a clickable link
html += "<a href=\"https://fmdx.org/\" target=\"_blank\">"; html += "<a href=\"https://fmdx.org/\" target=\"_blank\">";
html += "<img src=\"/logo.png\" alt=\"FMDX website\">"; html += "<img src=\"/logo.png\" alt=\"FMDX website\">";
html += "</a>"; html += "</a>";
@@ -130,7 +128,6 @@ void handleRoot() {
if (endIndex == -1) endIndex = line.length(); if (endIndex == -1) endIndex = line.length();
String cell = line.substring(startIndex, endIndex); String cell = line.substring(startIndex, endIndex);
// Extract PI code and Frequency
if (columnIndex == piCodeIndex) piCode = cell; if (columnIndex == piCodeIndex) piCode = cell;
if (columnIndex == frequencyIndex) frequency = cell; if (columnIndex == frequencyIndex) frequency = cell;
@@ -139,23 +136,17 @@ void handleRoot() {
columnIndex++; columnIndex++;
} }
// Remove " MHz" from Frequency
frequency.replace(" MHz", ""); frequency.replace(" MHz", "");
// Make row clickable
html += "<td><a href =\"https://maps.fmdx.org/#qth=&freq=" + frequency + "&findPi=" + piCode + "\"target=\"_blank\">🌐</a></td>"; html += "<td><a href =\"https://maps.fmdx.org/#qth=&freq=" + frequency + "&findPi=" + piCode + "\"target=\"_blank\">🌐</a></td>";
html += "</tr>"; html += "</tr>";
} }
} }
file.close(); file.close();
} else { } else html += "<tr><td colspan=\"100%\" style=\"text-align: center; color: red;\">" + String(textUI(299)) + "</td></tr>";
html += "<tr><td colspan=\"100%\" style=\"text-align: center; color: red;\">" + String(textUI(299)) + "</td></tr>";
}
if (!hasData) { if (!hasData) html += "<tr><td colspan=\"100%\" style=\"text-align: center; color: red;\">" + String(textUI(288)) + "</td></tr>";
html += "<tr><td colspan=\"100%\" style=\"text-align: center; color: red;\">" + String(textUI(288)) + "</td></tr>";
}
html += "</table>"; html += "</table>";
html += "</body></html>"; html += "</body></html>";
@@ -164,45 +155,30 @@ void handleRoot() {
} }
void handleDownloadCSV() { void handleDownloadCSV() {
// Attempt to open the CSV file from SPIFFS in read mode
fs::File file = SPIFFS.open("/logbook.csv", "r"); fs::File file = SPIFFS.open("/logbook.csv", "r");
// Check if the file was successfully opened
if (!file) { if (!file) {
// If the file could not be opened, send an error response
webserver.send(500, "text/plain", "Failed to open logbook for download"); webserver.send(500, "text/plain", "Failed to open logbook for download");
return; // Exit the function if the file cannot be opened return;
} }
// Set the headers to specify that the response will be a CSV file for download webserver.sendHeader("Content-Type", "text/csv");
webserver.sendHeader("Content-Type", "text/csv"); // Set MIME type for CSV files webserver.sendHeader("Content-Disposition", "attachment; filename=logbook.csv");
webserver.sendHeader("Content-Disposition", "attachment; filename=logbook.csv"); // Suggests the file name for download
// Stream the CSV file content directly to the browser
webserver.streamFile(file, "text/csv"); webserver.streamFile(file, "text/csv");
// Close the file after streaming the content to release resources
file.close(); file.close();
} }
bool handleCreateNewLogbook() { bool handleCreateNewLogbook() {
// Check if the file "logbook.csv" already exists
if (SPIFFS.exists("/logbook.csv")) { if (SPIFFS.exists("/logbook.csv")) {
// If it exists, delete the file if (!SPIFFS.remove("/logbook.csv")) return false;
if (!SPIFFS.remove("/logbook.csv")) {
return false;
}
} }
// Create a new "logbook.csv" file in write mode
fs::File file = SPIFFS.open("/logbook.csv", "w"); fs::File file = SPIFFS.open("/logbook.csv", "w");
if (!file) { if (!file) return false;
return false;
}
// Write the header to the new CSV file file.print("Date,Time,Frequency,PI,Signal,Stereo,TA,TP,PTY,ECC,PS,Radiotext\n");
String header = "Date,Time,Frequency,PI,Signal,Stereo,TA,TP,PTY,ECC,PS,Radiotext\n";
file.print(header);
file.flush(); file.flush();
file.close(); file.close();
@@ -215,33 +191,18 @@ bool handleCreateNewLogbook() {
} }
byte addRowToCSV() { byte addRowToCSV() {
// Ensure there is at least 150 bytes of free space in SPIFFS before proceeding if (SPIFFS.totalBytes() - SPIFFS.usedBytes() < 150 || logcounter > 1500) return 2;
if (SPIFFS.totalBytes() - SPIFFS.usedBytes() < 150 || logcounter > 1500) {
return 2; // Return 2 if insufficient free space is available
}
// Open the "logbook.csv" file in append mode
fs::File file = SPIFFS.open("/logbook.csv", "a"); fs::File file = SPIFFS.open("/logbook.csv", "a");
// Check if the file could not be opened if (!file) return 1;
if (!file) {
return 1; // Return 1 if the file cannot be opened
}
// Fetch the current date and time as a string
String currentDateTime = getCurrentDateTime(false); String currentDateTime = getCurrentDateTime(false);
if (currentDateTime == "") currentDateTime = "-,-";
// Use a placeholder ("-,-") if the date and time could not be retrieved
if (currentDateTime == "") {
currentDateTime = "-,-";
}
// Prepare the frequency in a formatted string (e.g., "XX.XX MHz")
int freqInt = (band == BAND_OIRT) ? (int)frequency_OIRT : (int)frequency; int freqInt = (band == BAND_OIRT) ? (int)frequency_OIRT : (int)frequency;
int adjustedFreq = freqInt + (band != BAND_OIRT ? ConverterSet * 100 : 0); int adjustedFreq = freqInt + (band != BAND_OIRT ? ConverterSet * 100 : 0);
String frequencyFormatted = String(adjustedFreq / 100) + "." + String frequencyFormatted = String(adjustedFreq / 100) + "." + ((adjustedFreq % 100 < 10) ? "0" : "") + String(adjustedFreq % 100) + " MHz";
((adjustedFreq % 100 < 10) ? "0" : "") +
String(adjustedFreq % 100) + " MHz";
// Calculate signal strength based on the selected unit // Calculate signal strength based on the selected unit
int SStatusPrint = 0; int SStatusPrint = 0;
@@ -249,126 +210,87 @@ byte addRowToCSV() {
else if (unit == 1) SStatusPrint = ((SStatus * 100) + 10875) / 100; // dBf else if (unit == 1) SStatusPrint = ((SStatus * 100) + 10875) / 100; // dBf
else if (unit == 2) SStatusPrint = round((float(SStatus) / 10.0 - 10.0 * log10(75) - 90.0) * 10.0); // dBm else if (unit == 2) SStatusPrint = round((float(SStatus) / 10.0 - 10.0 * log10(75) - 90.0) * 10.0); // dBm
// Format the signal strength with appropriate decimal places and unit
String signal = String(SStatusPrint / 10) + "." + String(abs(SStatusPrint % 10)); String signal = String(SStatusPrint / 10) + "." + String(abs(SStatusPrint % 10));
if (unit == 0) signal += " dBμV"; if (unit == 0) signal += " dBμV";
else if (unit == 1) signal += " dBf"; else if (unit == 1) signal += " dBf";
else if (unit == 2) signal += " dBm"; else if (unit == 2) signal += " dBm";
// Prepare the radio text with station information, including enhanced options if available
String radioText = String(radio.rds.stationText + " " + radio.rds.stationText32); String radioText = String(radio.rds.stationText + " " + radio.rds.stationText32);
if (radio.rds.hasEnhancedRT) { if (radio.rds.hasEnhancedRT) radioText += " eRT: " + String(radio.rds.enhancedRTtext);
radioText += " eRT: " + String(radio.rds.enhancedRTtext);
}
// Replace commas in the station name and radio text to avoid CSV conflicts
String stationName = radio.rds.stationName; String stationName = radio.rds.stationName;
String radioTextModified = (scanhold > 4 ? radioText : ""); String radioTextModified = (scanhold > 4 ? radioText : "");
stationName.replace(",", " "); // Replace commas in station name stationName.replace(",", " ");
radioTextModified.replace(",", " "); // Replace commas in radio text radioTextModified.replace(",", " ");
// Handle ECC, PTY, TA, TP, and Stereo flag
String TA = radio.rds.hasTA ? "" : " "; String TA = radio.rds.hasTA ? "" : " ";
String TP = radio.rds.hasTP ? "" : " "; String TP = radio.rds.TP ? "" : " ";
String Stereo = radio.getStereoStatus() ? "" : " "; String Stereo = radio.getStereoStatus() ? "" : " ";
String pty = String(radio.rds.stationTypeCode); String pty = String(radio.rds.PTY);
String ECC = "--"; String ECC = "--";
if (radio.rds.hasECC) { if (radio.rds.hasECC) {
char eccBuffer[3]; // Buffer to hold 2-digit hex value + null terminator char eccBuffer[3];
snprintf(eccBuffer, sizeof(eccBuffer), "%02X", radio.rds.ECC); // Format ECC as uppercase 2-digit hex snprintf(eccBuffer, sizeof(eccBuffer), "%02X", radio.rds.ECC); // Format ECC as uppercase 2-digit hex
ECC = String(eccBuffer); ECC = String(eccBuffer);
} }
// Construct the CSV row data String row = currentDateTime + "," + frequencyFormatted + "," + String(radio.rds.picode).substring(0, 4) + "," + signal + "," + Stereo + "," + TA + "," + TP + "," + pty + "," + ECC + "," + stationName + "," + radioTextModified + "\n";
String row = currentDateTime + "," +
frequencyFormatted + "," +
String(radio.rds.picode).substring(0, 4) + "," +
signal + "," +
Stereo + "," +
TA + "," +
TP + "," +
pty + "," +
ECC + "," +
stationName + "," +
radioTextModified + "\n";
// Write the row to the file and close it
if (file.print(row)) { if (file.print(row)) {
file.close(); // Successfully wrote to the file file.close();
logcounter++; logcounter++;
EEPROM.writeUInt(EE_UINT16_LOGCOUNTER, logcounter); EEPROM.writeUInt(EE_UINT16_LOGCOUNTER, logcounter);
EEPROM.commit(); EEPROM.commit();
return 0; // Return 0 to indicate success return 0;
} else { } else {
file.close(); // Close the file if writing fails file.close();
return 1; // Return 1 to indicate failure return 1;
} }
} }
String getCurrentDateTime(bool inUTC) { String getCurrentDateTime(bool inUTC) {
// Check if the RTC has been set if (!rtcset) return "-,-";
if (!rtcset) {
return "-,-"; // Return placeholder when the RTC is not set
}
// Use the ESP32's time functions to retrieve the current time
struct tm timeInfo; struct tm timeInfo;
if (!getLocalTime(&timeInfo)) { if (!getLocalTime(&timeInfo)) return "-,-";
return "-,-"; // Return placeholder if local time is unavailable
}
// Convert struct tm to time_t format
time_t currentEpoch = mktime(&timeInfo); time_t currentEpoch = mktime(&timeInfo);
// Determine UTC offset as a number
int utcOffsetHours = 0; int utcOffsetHours = 0;
if (!inUTC) { if (!inUTC) {
// Adjust for time zone offset and DST if not in UTC
currentEpoch += (NTPupdated ? NTPoffset * 3600 : radio.rds.offset); // Apply GMT offset if NTPupdated, else RDS offset currentEpoch += (NTPupdated ? NTPoffset * 3600 : radio.rds.offset); // Apply GMT offset if NTPupdated, else RDS offset
// Apply DST adjustment if NTPupdated and autoDST are true
if (NTPupdated && autoDST) { if (NTPupdated && autoDST) {
struct tm tempTimeInfo; struct tm tempTimeInfo;
localtime_r(&currentEpoch, &tempTimeInfo); // Convert to struct tm for DST calculation localtime_r(&currentEpoch, &tempTimeInfo);
if (isDST(mktime(&tempTimeInfo))) { // Check if DST is in effect if (isDST(mktime(&tempTimeInfo))) currentEpoch += 3600;
currentEpoch += 3600; // Add 1-hour DST offset
}
} }
} else utcOffsetHours = (NTPupdated ? NTPoffset : radio.rds.offset / 3600); } else utcOffsetHours = (NTPupdated ? NTPoffset : radio.rds.offset / 3600);
// Convert adjusted (or original) time back to struct tm format
localtime_r(&currentEpoch, &timeInfo); localtime_r(&currentEpoch, &timeInfo);
// Buffer for formatted date-time string
char buf[20]; char buf[20];
if (clockampm) { if (clockampm) {
// USA format: MM/DD/YYYY, HH:MM:SS AM/PM strftime(buf, sizeof(buf), "%m/%d/%Y", &timeInfo);
strftime(buf, sizeof(buf), "%m/%d/%Y", &timeInfo); // Format as MM/DD/YYYY
// Format time in 12-hour format with AM/PM
int hour = timeInfo.tm_hour; int hour = timeInfo.tm_hour;
String ampm = (hour >= 12) ? "PM" : "AM"; // Determine AM or PM String ampm = (hour >= 12) ? "PM" : "AM";
if (hour == 0) hour = 12; // Convert 0 hour to 12 AM if (hour == 0) hour = 12;
else if (hour > 12) hour -= 12; // Convert to 12-hour format for PM else if (hour > 12) hour -= 12;
String timeWithAMPM = String(hour) + ":" + (timeInfo.tm_min < 10 ? "0" : "") + String(timeInfo.tm_min) + ":" + (timeInfo.tm_sec < 10 ? "0" : "") + String(timeInfo.tm_sec) + " " + ampm; String timeWithAMPM = String(hour) + ":" + (timeInfo.tm_min < 10 ? "0" : "") + String(timeInfo.tm_min) + ":" + (timeInfo.tm_sec < 10 ? "0" : "") + String(timeInfo.tm_sec) + " " + ampm;
// Append UTC offset if inUTC
if (inUTC) { if (inUTC) {
String utcOffsetStr = ", " + String(utcOffsetHours) + ","; String utcOffsetStr = ", " + String(utcOffsetHours) + ",";
return String(buf) + "," + timeWithAMPM + utcOffsetStr; return String(buf) + "," + timeWithAMPM + utcOffsetStr;
} }
// Return the final formatted date and time for the USA region
return String(buf) + "," + timeWithAMPM; return String(buf) + "," + timeWithAMPM;
} else { } else {
// European format: DD-MM-YYYY, HH:MM:SS strftime(buf, sizeof(buf), "%d-%m-%Y", &timeInfo);
strftime(buf, sizeof(buf), "%d-%m-%Y", &timeInfo); // Format as DD-MM-YYYY
String timeEuropean = String(timeInfo.tm_hour) + ":" + (timeInfo.tm_min < 10 ? "0" : "") + String(timeInfo.tm_min) + ":" + (timeInfo.tm_sec < 10 ? "0" : "") + String(timeInfo.tm_sec); // Format time with leading zero if needed String timeEuropean = String(timeInfo.tm_hour) + ":" + (timeInfo.tm_min < 10 ? "0" : "") + String(timeInfo.tm_min) + ":" + (timeInfo.tm_sec < 10 ? "0" : "") + String(timeInfo.tm_sec); // Format time with leading zero if needed
// Append UTC offset if inUTC
if (inUTC) { if (inUTC) {
String utcOffsetStr = ", " + String(utcOffsetHours) + ","; String utcOffsetStr = ", " + String(utcOffsetHours) + ",";
return String(buf) + "," + timeEuropean + utcOffsetStr; return String(buf) + "," + timeEuropean + utcOffsetStr;
@@ -380,33 +302,24 @@ String getCurrentDateTime(bool inUTC) {
bool isDST(time_t t) { bool isDST(time_t t) {
struct tm timeInfo; struct tm timeInfo;
localtime_r(&t, &timeInfo); // Convert time_t to struct tm localtime_r(&t, &timeInfo);
int month = timeInfo.tm_mon + 1; // tm_mon is 0-based, so add 1 int month = timeInfo.tm_mon + 1;
int day = timeInfo.tm_mday; // tm_mday is the day of the month int day = timeInfo.tm_mday;
int hour = timeInfo.tm_hour; // tm_hour is the hour of the day int hour = timeInfo.tm_hour;
int weekday = timeInfo.tm_wday; // tm_wday is the day of the week (0 = Sunday) int weekday = timeInfo.tm_wday;
// DST starts last Sunday in March at 2:00 AM
if (month == 3) { if (month == 3) {
int lastSunday = 31 - ((weekday + 31 - day) % 7); int lastSunday = 31 - ((weekday + 31 - day) % 7);
if (day > lastSunday || (day == lastSunday && hour >= 2)) { if (day > lastSunday || (day == lastSunday && hour >= 2)) return true;
return true;
}
} }
// DST ends last Sunday in October at 3:00 AM
if (month == 10) { if (month == 10) {
int lastSunday = 31 - ((weekday + 31 - day) % 7); int lastSunday = 31 - ((weekday + 31 - day) % 7);
if (day < lastSunday || (day == lastSunday && hour < 3)) { if (day < lastSunday || (day == lastSunday && hour < 3)) return false;
return false;
}
} }
// DST is active from April to September if (month > 3 && month < 10) return true;
if (month > 3 && month < 10) {
return true;
}
return false; return false;
} }
@@ -422,48 +335,34 @@ void handleLogo() {
} }
void printLogbookCSV() { void printLogbookCSV() {
// Attempt to open the CSV file stored in SPIFFS
fs::File file = SPIFFS.open("/logbook.csv", "r"); fs::File file = SPIFFS.open("/logbook.csv", "r");
// Check if the file was successfully opened
if (!file) { if (!file) {
Serial.println("Failed to open logbook!"); Serial.println("Failed to open logbook!");
return; return;
} }
// Print a message indicating the start of the file content
Serial.println("===== Start of logbook.csv ====="); Serial.println("===== Start of logbook.csv =====");
// Read and print the contents of the file line by line
while (file.available()) { while (file.available()) {
String line = file.readStringUntil('\n'); // Read one line at a time String line = file.readStringUntil('\n');
Serial.println(line); // Print the line to the Serial Monitor Serial.println(line);
} }
// Close the file after reading
file.close(); file.close();
// Print a message indicating the end of the file content
Serial.println("===== End of logbook.csv ====="); Serial.println("===== End of logbook.csv =====");
} }
void sendUDPlog() { void sendUDPlog() {
// Get the current date and time as a string
String currentDateTime = getCurrentDateTime(true); String currentDateTime = getCurrentDateTime(true);
// Use a placeholder if the date and time could not be retrieved if (currentDateTime == "") currentDateTime = "-,-";
if (currentDateTime == "") {
currentDateTime = "-,-";
}
// Format the frequency, adjusting based on the band and converter settings
int freqInt = (band == BAND_OIRT) ? (int)frequency_OIRT : (int)frequency; int freqInt = (band == BAND_OIRT) ? (int)frequency_OIRT : (int)frequency;
int adjustedFreq = freqInt + (band != BAND_OIRT ? ConverterSet * 100 : 0); int adjustedFreq = freqInt + (band != BAND_OIRT ? ConverterSet * 100 : 0);
String frequencyFormatted = String(adjustedFreq / 100) + "." + String frequencyFormatted = String(adjustedFreq / 100) + "." + ((adjustedFreq % 100 < 10) ? "0" : "") + String(adjustedFreq % 100);
((adjustedFreq % 100 < 10) ? "0" : "") +
String(adjustedFreq % 100);
// Calculate signal strength and format it with the selected unit
int SStatusPrint = 0; int SStatusPrint = 0;
if (unit == 0) SStatusPrint = SStatus; // dBμV if (unit == 0) SStatusPrint = SStatus; // dBμV
else if (unit == 1) SStatusPrint = ((SStatus * 100) + 10875) / 100; // dBf else if (unit == 1) SStatusPrint = ((SStatus * 100) + 10875) / 100; // dBf
@@ -474,19 +373,14 @@ void sendUDPlog() {
else if (unit == 1) signal += " dBf"; else if (unit == 1) signal += " dBf";
else if (unit == 2) signal += " dBm"; else if (unit == 2) signal += " dBm";
// Prepare the radio text with RDS station information and enhanced options
String radioText = String(radio.rds.stationText + " " + radio.rds.stationText32); String radioText = String(radio.rds.stationText + " " + radio.rds.stationText32);
if (radio.rds.hasEnhancedRT) { if (radio.rds.hasEnhancedRT) radioText += " eRT: " + String(radio.rds.enhancedRTtext);
radioText += " eRT: " + String(radio.rds.enhancedRTtext);
}
// Replace commas in the station name and radio text to avoid conflicts in the CSV format
String stationName = radio.rds.stationName; String stationName = radio.rds.stationName;
stationName.replace(",", " "); stationName.replace(",", " ");
String radioTextModified = radioText; String radioTextModified = radioText;
radioTextModified.replace(",", " "); radioTextModified.replace(",", " ");
// Extract and format ECC (Extended Country Code) if available
String ECC = ""; String ECC = "";
if (radio.rds.hasECC) { if (radio.rds.hasECC) {
char eccBuffer[3]; char eccBuffer[3];
@@ -494,16 +388,13 @@ void sendUDPlog() {
ECC = String(eccBuffer); ECC = String(eccBuffer);
} }
// Format the list of Alternative Frequencies (AF) if available
String AF = ""; String AF = "";
if (radio.rds.hasAF && radio.af_counter > 0) { if (radio.rds.hasAF && radio.af_counter > 0) {
for (byte i = 0; i < radio.af_counter; i++) { for (byte i = 0; i < radio.af_counter; i++) {
AF += String(radio.af[i].frequency / 100) + "." + String((radio.af[i].frequency % 100) / 10) + AF += String(radio.af[i].frequency / 100) + "." + String((radio.af[i].frequency % 100) / 10) + (i == radio.af_counter - 1 ? "" : ";");
(i == radio.af_counter - 1 ? "" : ";");
} }
} }
// Format Enhanced Other Networks (EON) data if available
String EON = ""; String EON = "";
if (radio.eon_counter > 0) { if (radio.eon_counter > 0) {
for (byte i = 0; i < radio.eon_counter; i++) { for (byte i = 0; i < radio.eon_counter; i++) {
@@ -516,7 +407,6 @@ void sendUDPlog() {
} }
} }
// set Chipmodel
String CHIP = ""; String CHIP = "";
switch (chipmodel) { switch (chipmodel) {
case 0: CHIP = "TEF6686"; break; case 0: CHIP = "TEF6686"; break;
@@ -525,11 +415,8 @@ void sendUDPlog() {
case 3: CHIP = "TEF6689"; break; case 3: CHIP = "TEF6689"; break;
} }
// Extract RT+ (RadioText Plus) content if available
String RTPLUS = ""; String RTPLUS = "";
if (radio.rds.hasRDSplus) { if (radio.rds.hasRTplus) RTPLUS += radio.rds.RTContent1 + ";" + radio.rds.RTContent2;
RTPLUS += radio.rds.RTContent1 + ";" + radio.rds.RTContent2;
}
// Construct the data row to send via UDP // Construct the data row to send via UDP
String row = CHIP + "," + String row = CHIP + "," +
@@ -541,9 +428,9 @@ void sendUDPlog() {
signal + "," + signal + "," +
String(radio.getStereoStatus()) + "," + String(radio.getStereoStatus()) + "," +
String(radio.rds.hasTA) + "," + String(radio.rds.hasTA) + "," +
String(radio.rds.hasTP) + "," + String(radio.rds.TP) + "," +
String(radio.rds.hasTMC) + "," + String(radio.rds.hasTMC) + "," +
String(radio.rds.stationTypeCode) + "," + String(radio.rds.PTY) + "," +
ECC + "," + ECC + "," +
stationName + "," + stationName + "," +
radioTextModified + "," + radioTextModified + "," +
+14 -28
View File
@@ -5110,17 +5110,12 @@ void StoreMemoryPos(uint8_t _pos) {
EEPROM.writeByte(_pos + EE_PRESETS_BAND_START, band); EEPROM.writeByte(_pos + EE_PRESETS_BAND_START, band);
EEPROM.writeByte(_pos + EE_PRESET_BW_START, BWset); EEPROM.writeByte(_pos + EE_PRESET_BW_START, BWset);
EEPROM.writeByte(_pos + EE_PRESET_MS_START, StereoToggle); EEPROM.writeByte(_pos + EE_PRESET_MS_START, StereoToggle);
if (band == BAND_FM) {//todo air
EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency); if (band == BAND_FM) EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency);
} else if (band == BAND_OIRT) { else if (band == BAND_OIRT) EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency_OIRT);
EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency_OIRT); else if (band == BAND_LW) EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency_LW);
} else if (band == BAND_LW) { else if (band == BAND_MW) EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency_MW);
EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency_LW); else EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency_SW);
} else if (band == BAND_MW) {
EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency_MW);
} else {
EEPROM.writeUInt((_pos * 4) + EE_PRESETS_FREQUENCY_START, frequency_SW);
}
presets[_pos].band = band; presets[_pos].band = band;
presets[_pos].bw = BWset; presets[_pos].bw = BWset;
@@ -5144,17 +5139,11 @@ void StoreMemoryPos(uint8_t _pos) {
EEPROM.commit(); EEPROM.commit();
if (band == BAND_FM) {//todo air if (band == BAND_FM) presets[_pos].frequency = frequency;
presets[_pos].frequency = frequency; else if (band == BAND_OIRT) presets[_pos].frequency = frequency_OIRT;
} else if (band == BAND_OIRT) { else if (band == BAND_LW) presets[_pos].frequency = frequency_LW;
presets[_pos].frequency = frequency_OIRT; else if (band == BAND_MW) presets[_pos].frequency = frequency_MW;
} else if (band == BAND_LW) { else presets[_pos].frequency = frequency_SW;
presets[_pos].frequency = frequency_LW;
} else if (band == BAND_MW) {
presets[_pos].frequency = frequency_MW;
} else {
presets[_pos].frequency = frequency_SW;
}
} }
void ClearMemoryRange(uint8_t start, uint8_t stop) { void ClearMemoryRange(uint8_t start, uint8_t stop) {
@@ -5180,9 +5169,7 @@ void ClearMemoryRange(uint8_t start, uint8_t stop) {
} }
} }
byte numval[16] = { byte numval[16] = {2, 3, 127, 5, 6, 0, 9, 13, 8, 7, 4, 1, 0, 0, 0, 0};
2, 3, 127, 5, 6, 0, 9, 13, 8, 7, 4, 1, 0, 0, 0, 0
};
int GetNum() { int GetNum() {
int16_t temp; int16_t temp;
@@ -5201,12 +5188,11 @@ int GetNum() {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
if ((temp & 0x01) == 0) { if ((temp & 0x01) == 0) {
num = numval[i]; num = numval[i];
cnt ++; cnt++;
} }
temp >>= 1; temp >>= 1;
} }
if (cnt == 1) if (cnt == 1) return num;
return num;
} }
return -1; return -1;
+14 -14
View File
@@ -132,12 +132,12 @@ void ShowAdvancedRDS() {
} }
String rtplusstring; String rtplusstring;
if (radio.rds.hasRDSplus) rtplusstring = (radio.rds.rdsplusTag1 != 169 ? String(textUI(radio.rds.rdsplusTag1)) + ": " + String(radio.rds.RTContent1) : "") + (radio.rds.rdsplusTag2 != 169 ? " - " + String(textUI(radio.rds.rdsplusTag2)) + ": " + String(radio.rds.RTContent2) : "") + " "; else rtplusstring = textUI(89); if (radio.rds.hasRTplus) rtplusstring = (radio.rds.rdsplusTag1 != 169 ? String(textUI(radio.rds.rdsplusTag1)) + ": " + String(radio.rds.RTContent1) : "") + (radio.rds.rdsplusTag2 != 169 ? " - " + String(textUI(radio.rds.rdsplusTag2)) + ": " + String(radio.rds.RTContent2) : "") + " "; else rtplusstring = textUI(89);
if (hasrtplusold != radio.rds.hasRDSplus) { if (hasrtplusold != radio.rds.hasRTplus) {
if (!screenmute) { if (!screenmute) {
if (radio.rds.hasRDSplus) tftPrint(ALEFT, "RT+", 123, 51, RDSColor, RDSColorSmooth, 16); else tftPrint(ALEFT, "RT+", 123, 51, GreyoutColor, BackgroundColor, 16); if (radio.rds.hasRTplus) tftPrint(ALEFT, "RT+", 123, 51, RDSColor, RDSColorSmooth, 16); else tftPrint(ALEFT, "RT+", 123, 51, GreyoutColor, BackgroundColor, 16);
} }
hasrtplusold = radio.rds.hasRDSplus; hasrtplusold = radio.rds.hasRTplus;
} }
if (rtplusstring != rtplusstringold) { if (rtplusstring != rtplusstringold) {
@@ -172,11 +172,11 @@ void ShowAdvancedRDS() {
} }
} }
if (TPold != radio.rds.hasTP) { if (TPold != radio.rds.TP) {
if (!screenmute) { if (!screenmute) {
if (radio.rds.hasTP) tftPrint(ALEFT, "TP", 2, 51, RDSColor, RDSColorSmooth, 16); else tftPrint(ALEFT, "TP", 2, 51, GreyoutColor, BackgroundColor, 16); if (radio.rds.TP) tftPrint(ALEFT, "TP", 2, 51, RDSColor, RDSColorSmooth, 16); else tftPrint(ALEFT, "TP", 2, 51, GreyoutColor, BackgroundColor, 16);
} }
TPold = radio.rds.hasTP; TPold = radio.rds.TP;
} }
if (TAold != radio.rds.hasTA) { if (TAold != radio.rds.hasTA) {
@@ -193,10 +193,10 @@ void ShowAdvancedRDS() {
afmethodBold = radio.afmethodB; afmethodBold = radio.afmethodB;
} }
if (rdsblockold != radio.rdsblock) { if (rdsblockold != radio.rdsgroup) {
if (rdsblockold < 33) tft.fillCircle((6 * rdsblockold) + 10, 133, 2, SignificantColor); if (rdsblockold < 33) tft.fillCircle((6 * rdsblockold) + 10, 133, 2, SignificantColor);
if (radio.rdsblock < 33) tft.fillCircle((6 * radio.rdsblock) + 10, 133, 2, InsignificantColor); if (radio.rdsgroup < 33) tft.fillCircle((6 * radio.rdsgroup) + 10, 133, 2, InsignificantColor);
rdsblockold = radio.rdsblock; rdsblockold = radio.rdsgroup;
} }
if (hastmcold != radio.rds.hasTMC) { if (hastmcold != radio.rds.hasTMC) {
@@ -527,9 +527,9 @@ void showPI() {
void showPTY() { void showPTY() {
if (strcmp(radio.rds.stationType, programTypePrevious)) { if (strcmp(radio.rds.stationType, programTypePrevious)) {
String PTYString = String(radio.rds.stationTypeCode) + "/" + (radio.rds.region != 0 ? radio.rds.stationType : textUI(228 + radio.rds.stationTypeCode)); String PTYString = String(radio.rds.PTY) + "/" + (radio.rds.region != 0 ? radio.rds.stationType : textUI(228 + radio.rds.PTY));
if (radio.rds.stationTypeCode == 32) PTYString = ""; if (radio.rds.PTY == 32) PTYString = "";
if (!screenmute) { if (!screenmute) {
if (advancedRDS) { if (advancedRDS) {
@@ -545,7 +545,7 @@ void showPTY() {
if (wifi) { if (wifi) {
Udp.beginPacket(remoteip, 9030); Udp.beginPacket(remoteip, 9030);
Udp.print("from=TEF_tuner_" + String(stationlistid, DEC) + ";PTY="); Udp.print("from=TEF_tuner_" + String(stationlistid, DEC) + ";PTY=");
Udp.print(String(radio.rds.stationTypeCode, HEX)); Udp.print(String(radio.rds.PTY, HEX));
Udp.endPacket(); Udp.endPacket();
} }
strcpy(programTypePrevious, radio.rds.stationType); strcpy(programTypePrevious, radio.rds.stationType);
@@ -1015,7 +1015,7 @@ void ShowRDSStatistics() {
const uint8_t rdsYpos[] PROGMEM = {56, 76, 96, 116, 136, 156, 176, 196}; const uint8_t rdsYpos[] PROGMEM = {56, 76, 96, 116, 136, 156, 176, 196};
uint8_t rb = radio.rdsblock; uint8_t rb = radio.rdsgroup;
uint16_t xpos, xposPct; uint16_t xpos, xposPct;
if(rb <= RDS_GROUP_3B) { if(rb <= RDS_GROUP_3B) {