From 6f97d420e79eb93813df61b36deafcf2143792b3 Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Wed, 7 Jan 2026 17:41:20 +0100 Subject: [PATCH] "Ah, yeah! This is happenin!' - Sonic the Hedgehog, 1998 --- include/TEF6686.h | 9 ++-- include/globals.h | 1 - include/rds.h | 134 ---------------------------------------------- platformio.ini | 1 + src/TEF6686.cpp | 79 ++++++++++++++++----------- src/globals.cpp | 1 - src/gui.cpp | 3 -- src/logbook.cpp | 4 +- src/rds.cpp | 12 ++--- 9 files changed, 61 insertions(+), 183 deletions(-) diff --git a/include/TEF6686.h b/include/TEF6686.h index 4074af2..5bfaf16 100644 --- a/include/TEF6686.h +++ b/include/TEF6686.h @@ -4,6 +4,7 @@ #include "Tuner_Drv_Lithio.h" #include "Tuner_Interface.h" #include "RdsPiBuffer.hpp" +#include "change_detector.h" extern const unsigned char tuner_init_tab[] PROGMEM; extern const unsigned char tuner_init_tab9216[] PROGMEM; @@ -367,7 +368,7 @@ static const char* const oda_app_names[] { "To warn people in case of disasters or emergency", "Personal weather station", "Hybradio RDS-Net (for testing use, only)", - "RDS2 – 9 bit AF lists ODA", + "RDS2 - 9 bit AF lists ODA", "Enhanced RadioText / eRT", "Warning receiver", "Enhanced early warning system", @@ -479,13 +480,13 @@ typedef struct _rds_ { bool hasTA; bool hasEON; bool hasAID; - bool hasTMC; + Detector hasTMC{false}; bool hasAF; bool hasCT; bool hasPTYN; bool rtAB; bool rtAB32; - bool hasRTplus; + Detector hasRTplus{false}; bool filter; bool rdsreset; bool pierrors; @@ -529,7 +530,7 @@ typedef struct _logbook_ { class TEF6686 { public: - af_ af[51]; + af_ af[51]; eon_ eon[21]; rds_ rds; logbook_ logbook[22]; diff --git a/include/globals.h b/include/globals.h index fa7ed43..8246395 100644 --- a/include/globals.h +++ b/include/globals.h @@ -48,7 +48,6 @@ extern bool firstTouchHandled; extern bool flashing; extern bool fmsi, fullsearchrds; extern bool hasafold, hasCTold, haseonold; -extern bool hasrtplusold, hastmcold; extern bool initdxscan, invertdisplay, leave; extern bool LowLevelInit; extern bool memorystore; diff --git a/include/rds.h b/include/rds.h index 3edc238..32ee038 100644 --- a/include/rds.h +++ b/include/rds.h @@ -8,140 +8,6 @@ #include #include "globals.h" -extern bool advancedRDS; -extern bool afmethodBold; -extern bool afpage; -extern bool afscreen; -extern bool aftest; -extern bool autoDST; -extern bool artheadold; -extern bool BWreset; -extern bool compressedold; -extern bool clearrds; -extern bool clockampm; -extern bool dropout; -extern bool dynamicPTYold; -extern bool fullsearchrds; -extern bool hasafold; -extern bool hasCTold; -extern bool haseonold; -extern bool hasrtplusold; -extern bool hastmcold; -extern bool memreset; -extern bool NTPupdated; -extern bool rdsreset; -extern bool RDSSPYTCP; -extern bool RDSSPYUSB; -extern bool rdsstatscreen; -extern bool rdsstereoold; -extern bool rtcset; -extern bool screenmute; -extern bool setupmode; -extern bool showclock; -extern bool showlongps; -extern bool TAold; -extern bool TPold; -extern bool wifi; -extern bool XDRGTKTCP; -extern bool XDRGTKUSB; -extern byte af_counterold; -extern byte aid_counterold; -extern byte afpagenr; -extern byte band; -extern byte charwidth; -extern byte CurrentSkin; -extern byte ECCold; -extern byte language; -extern byte eonptyold[20]; -extern byte rdsblockold; -extern byte rdsqualityold; -extern byte showrdserrors; -extern byte stationlistid; -extern byte programTypePrevious; -extern char eonpicodeold[20][6]; -extern int ActiveColor; -extern int ActiveColorSmooth; -extern int BackgroundColor; -extern int BackgroundColor1; -extern int BackgroundColor2; -extern int BackgroundColor4; -extern int BarSignificantColor; -extern int BarInsignificantColor; -extern int berPercentold; -extern int BWAutoColor; -extern int BWAutoColorSmooth; -extern int FrameColor; -extern int FreqColor; -extern int FreqColorSmooth; -extern int GreyoutColor; -extern int InsignificantColor; -extern int InsignificantColorSmooth; -extern int PrimaryColor; -extern int PrimaryColorSmooth; -extern int RDSColor; -extern int RDSColorSmooth; -extern int RDSDropoutColor; -extern int RDSDropoutColorSmooth; -extern int SecondaryColor; -extern int SecondaryColorSmooth; -extern int SignificantColor; -extern int SignificantColorSmooth; -extern int xPos; -extern int xPos2; -extern int xPos3; -extern int xPos4; -extern int xPos5; -extern int xPos6; -extern int8_t NTPoffset; -extern int16_t SAvg3; -extern IPAddress remoteip; -extern String AIDString; -extern String ECColdString; -extern String ECCString; -extern String eonpsold[20]; -extern String PIold; -extern String PSold; -extern String ptynold; -extern String PTYold; -extern String rds_clock; -extern String rds_clockold; -extern String rds_date; -extern String rds_dateold; -extern String RDSSPYRDS; -extern String RDSSPYRDSold; -extern String RTold; -extern String stationIDold; -extern String stationStateold; -extern String XDRGTKRDS; -extern String XDRGTKRDSold; -extern unsigned int mappedfreqold[20]; -extern unsigned int mappedfreqold2[20]; -extern unsigned int mappedfreqold3[20]; -extern unsigned long afticker; -extern unsigned long aftickerhold; -extern unsigned long aftimer; -extern unsigned long blockcounterold[33]; -extern unsigned long eccticker; -extern unsigned long ecctickerhold; -extern unsigned long eonticker; -extern unsigned long eontickerhold; -extern unsigned long processed_rdsblocksold[33]; -extern unsigned long pslongticker; -extern unsigned long pslongtickerhold; -extern unsigned long rtplusticker; -extern unsigned long rtplustickerhold; -extern unsigned long rtticker; -extern unsigned long rttickerhold; - -extern ESP32Time rtc; -extern TFT_eSPI tft; -extern TEF6686 radio; -extern WiFiClient RemoteClient; -extern WiFiUDP Udp; -extern TFT_eSprite FullLineSprite; -extern TFT_eSprite RDSSprite; -extern TFT_eSprite PSSprite; - void ShowAdvancedRDS(); void readRds(); void doAF(); diff --git a/platformio.ini b/platformio.ini index eaad620..2d4aa78 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,6 +10,7 @@ [env:esp32dev] platform = espressif32 +upload_speed = 921600 board = esp32dev framework = arduino board_build.partitions = huge_app.csv diff --git a/src/TEF6686.cpp b/src/TEF6686.cpp index bdd0a92..b2f6a42 100644 --- a/src/TEF6686.cpp +++ b/src/TEF6686.cpp @@ -35,7 +35,7 @@ void TEF6686::TestAFEON() { delay(187); devTEF_Radio_Get_RDS_Status(&rds.rdsStat, &rds.rdsA, &rds.rdsB, &rds.rdsC, &rds.rdsD, &rds.rdsErr); - if (rds.rdsStat & (1 << 9)) { + if (bitRead(rds.rdsStat, 9)) { if ((afmethodB && rds.afreg ? (((rds.rdsA >> 8) & 0xF) > 2 && ((rds.correctPI >> 8) & 0xF) > 2 && ((rds.rdsA >> 12) & 0xF) == ((rds.correctPI >> 12) & 0xF) && (rds.rdsA & 0xFF) == (rds.correctPI & 0xFF)) || rds.rdsA == rds.correctPI : rds.rdsA == rds.correctPI)) { af[x].checked = true; af[x].afvalid = true; @@ -85,7 +85,7 @@ uint16_t TEF6686::TestAF() { devTEF_Set_Cmd(TEF_FM, Cmd_Tune_To, 7, 4, af[highestIndex].frequency); delay(187); devTEF_Radio_Get_RDS_Status(&rds.rdsStat, &rds.rdsA, &rds.rdsB, &rds.rdsC, &rds.rdsD, &rds.rdsErr); - if (rds.rdsStat & (1 << 9)) { + if (bitRead(rds.rdsStat, 9)) { if ((afmethodB && rds.afreg ? (((rds.rdsA >> 8) & 0xF) > 2 && ((rds.correctPI >> 8) & 0xF) > 2 && ((rds.rdsA >> 12) & 0xF) == ((rds.correctPI >> 12) & 0xF) && (rds.rdsA & 0xFF) == (rds.correctPI & 0xFF)) || rds.rdsA == rds.correctPI : rds.rdsA == rds.correctPI)) { currentfreq = af[highestIndex].frequency; for (byte y = 0; y < 50; y++) { @@ -337,49 +337,61 @@ void TEF6686::getStatusAM(int16_t *level, uint16_t *noise, uint16_t *cochannel, } void TEF6686::readRDS(byte showrdserrors) { - 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) 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; devTEF_Radio_Get_RDS_Data(&rds.rdsStat, &rds.rdsA, &rds.rdsB, &rds.rdsC, &rds.rdsD, &rds.rdsErr); - if ((rds.rdsStat & (1 << 14))) { + if(bitRead(rds.rdsStat, 14)) { for (int i = 0; i < 22; i++) devTEF_Radio_Get_RDS_Data(&rds.rdsStat, &rds.rdsA, &rds.rdsB, &rds.rdsC, &rds.rdsD, &rds.rdsErr); } } } - if (bitRead(rds.rdsStat, 9)) { + + if(bitRead(rds.rdsStat, 9)) { rds.hasRDS = true; bitStartTime = 0; } else { - if (bitStartTime == 0) bitStartTime = millis(); - else if (millis() - bitStartTime >= 87) rds.hasRDS = false; + if(bitStartTime == 0) bitStartTime = millis(); + else if(millis() - bitStartTime >= 87) rds.hasRDS = false; + return; // No sync means no data, ever! Unless sync status changes of course } + if(bitRead(rds.rdsStat, 15) == 0) return; // No data, no fucks + rdsAerrorThreshold = ((rds.rdsErr >> 14) & 0x03) > showrdserrors; rdsBerrorThreshold = ((rds.rdsErr >> 12) & 0x03) > showrdserrors; rdsCerrorThreshold = ((rds.rdsErr >> 10) & 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)) { - rds.rdsAerror = (((rds.rdsErr >> 14) & 0x03) > 1); - rds.rdsBerror = (((rds.rdsErr >> 12) & 0x03) > 1); - rds.rdsCerror = (((rds.rdsErr >> 10) & 0x03) > 1); - rds.rdsDerror = (((rds.rdsErr >> 8) & 0x03) > 1); + uint16_t pi = 0; + if(!rdsAerrorThreshold) pi = rds.rdsA; // Standard, if we have group A with block A available + else if(bitRead(rds.rdsStat, 12) && !rdsCerrorThreshold) { + // Little less standard. RDS type B groups always have PI in blocks A and C, it helps that block c of group b checkword is diffrent from the group a checkword, the tef has flag for that + // If a station broadcasts B groups often then their PI code could get received easier in bad conditions + pi = rds.rdsC; + } - if (!rdsAerrorThreshold && afreset) { - rds.correctPI = rds.rdsA; + if ((rds.rdsA != previous_rdsA || rds.rdsB != previous_rdsB || rds.rdsC != previous_rdsC || rds.rdsD != previous_rdsD)) { + rds.rdsAerror = ((rds.rdsErr >> 14) & 0x03) > 1; + rds.rdsBerror = ((rds.rdsErr >> 12) & 0x03) > 1; + rds.rdsCerror = ((rds.rdsErr >> 10) & 0x03) > 1; + rds.rdsDerror = ((rds.rdsErr >> 8) & 0x03) > 1; + + if (pi != 0 && afreset) { + rds.correctPI = pi; afreset = false; } - if (((!rdsAerrorThreshold && !rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) || (rds.pierrors && !errorfreepi))) { - if (piold == 0 || rds.rdsA != piold) { - piold = rds.rdsA; - rds.picode[0] = (rds.rdsA >> 12) & 0xF; - rds.picode[1] = (rds.rdsA >> 8) & 0xF; - rds.picode[2] = (rds.rdsA >> 4) & 0xF; - rds.picode[3] = rds.rdsA & 0xF; + if (pi != 0 || (rds.pierrors && !errorfreepi)) { + if (piold == 0 || pi != piold) { + piold = pi; + rds.picode[0] = (pi >> 12) & 0xF; + rds.picode[1] = (pi >> 8) & 0xF; + rds.picode[2] = (pi >> 4) & 0xF; + rds.picode[3] = pi & 0xF; for (int i = 0; i < 4; i++) { if (rds.picode[i] < 10) rds.picode[i] += '0'; else rds.picode[i] += 'A' - 10; @@ -464,7 +476,7 @@ void TEF6686::readRDS(byte showrdserrors) { } if (!foundMatch) { - uint16_t stationID = rds.rdsA; + uint16_t stationID = pi; // If stationID is greater than 4096 if (stationID > 4096) { @@ -515,9 +527,12 @@ void TEF6686::readRDS(byte showrdserrors) { } } - if (rds.rdsBerror && showrdserrors != 3) goto end; + // B errors mean we can't reliably tell what this is, don't risk it. + // And also make sure we have data in the first place, then the decoder first starts it could send just the pi code with nothing more + if ((rds.rdsBerror && showrdserrors != 3) && bitRead(rds.rdsStat, 13) == 0) goto end; rdsgroup = rds.rdsB >> 11; // Includes version bit as LSB, better for the switch statement + if(bitRead(rds.rdsStat, 12) && (rdsgroup & 1) == 0) goto end; // Modulation says type B, but data says otherwise? Dunno what to treat it as, thus skip rds.TP = (bitRead(rds.rdsB, 10)); rds.PTY = (rds.rdsB >> 5) & 0x1F; @@ -1175,10 +1190,10 @@ void TEF6686::readRDS(byte showrdserrors) { rds.aid_counter++; } - if (rds.rdsD == 0xCD46) rds.hasTMC = true; + if (rds.rdsD == 0xCD46) rds.hasTMC.set(true); if (rds.rdsD == 0x4BD7) { - rds.hasRTplus = true; + rds.hasRTplus.set(true); rtplusblock = ((rds.rdsB & 0x1F) >> 1) * 2; } @@ -1196,7 +1211,7 @@ void TEF6686::readRDS(byte showrdserrors) { } break; 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 == pi || rds.PICTlock == 0)) { uint32_t mjd = (rds.rdsB & 0x03) << 15 | ((rds.rdsC >> 1) & 0x7FFF);; uint16_t hour, minute, day = 5, month = 1, year = 2026; int32_t timeoffset; @@ -1270,7 +1285,7 @@ void TEF6686::readRDS(byte showrdserrors) { case RDS_GROUP_11A: case RDS_GROUP_12A: case RDS_GROUP_13A: { - if ((!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) && rtplusblock == rdsgroup && rds.hasRTplus) { + if ((!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) && rtplusblock == rdsgroup && rds.hasRTplus.get()) { rds.rdsplusTag1 = ((rds.rdsB & 0x07) << 3) + (rds.rdsC >> 13); rds.rdsplusTag2 = ((rds.rdsC & 0x01) << 5) + (rds.rdsD >> 11); uint16_t start_marker_1 = (rds.rdsC >> 7) & 0x3F; @@ -1347,7 +1362,7 @@ void TEF6686::readRDS(byte showrdserrors) { } } - if (!rdsBerrorThreshold && rdsgroup == 16 && (bitRead(rds.rdsB, 15))) rds.hasTMC = true; + if (!rdsBerrorThreshold && rdsgroup == RDS_GROUP_8A && (bitRead(rds.rdsB, 15))) rds.hasTMC.set(true); if ((!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold) && DABAFblock == rdsgroup && rds.hasDABAF) { rds.dabaffreq = (rds.rdsC * 16); @@ -1586,9 +1601,11 @@ void TEF6686::clearRDS(bool fullsearchrds) { rds.PTY = 32; rds.hasECC = rds.hasRT = rds.hasRDS = false; rds.TP = rds.hasAF = rds.hasTA = false; - rds.hasEON = rds.hasCT = rds.hasTMC = false; + rds.hasEON = rds.hasCT = false; rds.hasAID = rds.hasPTYN = rds.hasLongPS = false; - rds.hasRTplus = rds.hasDABAF = rds.hasEnhancedRT = false; + rds.hasRTplus.set(false); + rds.hasTMC.set(false); + rds.hasDABAF = rds.hasEnhancedRT = false; rt_process = ps_process = pslong_process = false; rds.rdsreset = true; rds.hasArtificialhead = rds.hasCompressed = false; diff --git a/src/globals.cpp b/src/globals.cpp index c90a7e1..7eccdf6 100644 --- a/src/globals.cpp +++ b/src/globals.cpp @@ -29,7 +29,6 @@ bool firstTouchHandled = false; bool flashing; bool fmsi, fullsearchrds; bool hasafold, hasCTold, haseonold; -bool hasrtplusold, hastmcold; bool initdxscan, invertdisplay, leave; bool LowLevelInit; bool memorystore; diff --git a/src/gui.cpp b/src/gui.cpp index 4b45320..625d34c 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -2984,7 +2984,6 @@ void BuildAdvancedRDS() { af_counterold = 254; TAold = false; TPold = false; - hastmcold = false; dynamicPTYold = false; artheadold = false; compressedold = false; @@ -2992,7 +2991,6 @@ void BuildAdvancedRDS() { hasafold = false; haseonold = false; BWreset = true; - hasrtplusold = false; afmethodBold = false; rds_clockold = ""; dropout = false; @@ -3108,7 +3106,6 @@ void BuildDisplay() { batteryold = 6; batteryVold = 0; vPerold = 0; - hasrtplusold = false; TAold = false; TPold = false; haseonold = false; diff --git a/src/logbook.cpp b/src/logbook.cpp index 9a0f5b6..5c0d1aa 100644 --- a/src/logbook.cpp +++ b/src/logbook.cpp @@ -412,13 +412,13 @@ void sendUDPlog() { } String RTPLUS = ""; - if (radio.rds.hasRTplus) RTPLUS += radio.rds.RTContent1 + ";" + radio.rds.RTContent2; + if (radio.rds.hasRTplus.get()) RTPLUS += radio.rds.RTContent1 + ";" + radio.rds.RTContent2; // Construct the data row to send via UDP String row = CHIP + "," + VERSION + "," + String(scandxmode) + "," + currentDateTime + "," + frequencyFormatted + "," + String(radio.rds.picode).substring(0, 4) + "," + signal + "," + String(radio.getStereoStatus()) + "," + String(radio.rds.hasTA) + "," + - String(radio.rds.TP) + "," + String(radio.rds.hasTMC) + "," + String(radio.rds.PTY) + "," + + String(radio.rds.TP) + "," + String(radio.rds.hasTMC.get()) + "," + String(radio.rds.PTY) + "," + ECC + "," + stationName + "," + radioTextModified + "," + AF + "," + EON + "," + RTPLUS + "\n"; diff --git a/src/rds.cpp b/src/rds.cpp index 957cb23..a3e8d2f 100644 --- a/src/rds.cpp +++ b/src/rds.cpp @@ -147,12 +147,11 @@ void ShowAdvancedRDS() { } String rtplusstring; - 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.hasRTplus) { + if (radio.rds.hasRTplus.get()) 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.changed(0)) { if (!screenmute) { - if (radio.rds.hasRTplus) tftPrint(ALEFT, "RT+", 123, 51, RDSColor, RDSColorSmooth, 16); else tftPrint(ALEFT, "RT+", 123, 51, GreyoutColor, BackgroundColor, 16); + if (radio.rds.hasRTplus.get()) tftPrint(ALEFT, "RT+", 123, 51, RDSColor, RDSColorSmooth, 16); else tftPrint(ALEFT, "RT+", 123, 51, GreyoutColor, BackgroundColor, 16); } - hasrtplusold = radio.rds.hasRTplus; } if (rtplusstring != rtplusstringold) { @@ -214,11 +213,10 @@ void ShowAdvancedRDS() { rdsblockold = radio.rdsgroup; } - if (hastmcold != radio.rds.hasTMC) { + if (radio.rds.hasTMC.changed(0)) { if (!screenmute) { - if (radio.rds.hasTMC) tftPrint(ALEFT, "TMC", 88, 51, RDSColor, RDSColorSmooth, 16); else tftPrint(ALEFT, "TMC", 88, 51, GreyoutColor, BackgroundColor, 16); + if (radio.rds.hasTMC.get()) tftPrint(ALEFT, "TMC", 88, 51, RDSColor, RDSColorSmooth, 16); else tftPrint(ALEFT, "TMC", 88, 51, GreyoutColor, BackgroundColor, 16); } - hastmcold = radio.rds.hasTMC; } rdsreset = false;