From f3383194cb4f6dc2197c6580dda1cf19dd6fdf7c Mon Sep 17 00:00:00 2001 From: James LeRoy Date: Tue, 7 Apr 2020 15:06:29 -0500 Subject: [PATCH] Date and time with MJD and example usage --- examples/SerialRadio/SerialRadio.ino | 86 +++++++++++++++++++---- src/RDSParser.cpp | 100 ++++++++++++++++----------- src/RDSParser.h | 10 +-- 3 files changed, 138 insertions(+), 58 deletions(-) mode change 100644 => 100755 examples/SerialRadio/SerialRadio.ino mode change 100644 => 100755 src/RDSParser.cpp mode change 100644 => 100755 src/RDSParser.h diff --git a/examples/SerialRadio/SerialRadio.ino b/examples/SerialRadio/SerialRadio.ino old mode 100644 new mode 100755 index bce4f19..8b13320 --- a/examples/SerialRadio/SerialRadio.ino +++ b/examples/SerialRadio/SerialRadio.ino @@ -1,7 +1,7 @@ /// -/// \file SerialRadio.ino +/// \file SerialRadio.ino /// \brief Radio implementation using the Serial communication. -/// +/// /// \author Matthias Hertel, http://www.mathertel.de /// \copyright Copyright (c) 2014 by Matthias Hertel.\n /// This work is licensed under a BSD style license.\n @@ -16,10 +16,10 @@ /// ------ /// The necessary wiring of the various chips are described in the Testxxx example sketches. /// The boards have to be connected by using the following connections: -/// +/// /// Arduino port | SI4703 signal | RDA5807M signal /// :----------: | :-----------: | :-------------: -/// GND (black) | GND | GND +/// GND (black) | GND | GND /// 3.3V (red) | VCC | VCC /// 5V (red) | - | - /// A5 (yellow) | SCLK | SCLK @@ -76,8 +76,8 @@ int i_sidx = 5; ///< Start at Station with index=5 /// by uncommenting the right radio object definition. // RADIO radio; ///< Create an instance of a non functional radio. -RDA5807M radio; ///< Create an instance of a RDA5807 chip radio -// SI4703 radio; ///< Create an instance of a SI4703 chip radio. +// RDA5807M radio; ///< Create an instance of a RDA5807 chip radio +SI4703 radio; ///< Create an instance of a SI4703 chip radio. //SI4705 radio; ///< Create an instance of a SI4705 chip radio. // TEA5767 radio; ///< Create an instance of a TEA5767 chip radio. @@ -85,6 +85,14 @@ RDA5807M radio; ///< Create an instance of a RDA5807 chip radio /// get a RDS parser RDSParser rds; +/// Modified Julian Day from RDS Time +typedef struct MJD_INFO { + int month; + int day; + int year; +}; + +MJD_INFO mjd_info; /// State definition for this radio implementation. enum RADIO_STATE { @@ -100,7 +108,7 @@ RADIO_STATE state; ///< The state variable is used for parsing input characters. -/// Update the Frequency on the LCD display. +/// Update the Frequency void DisplayFrequency(RADIO_FREQ f) { char s[12]; @@ -109,13 +117,60 @@ void DisplayFrequency(RADIO_FREQ f) } // DisplayFrequency() -/// Update the ServiceName text on the LCD display. -void DisplayServiceName(char *name) +/// Update the ServiceName text +void DisplayRDSServiceName(char *name) { - Serial.print("RDS:"); + Serial.print("RDS ServiceName:"); Serial.println(name); -} // DisplayServiceName() +} // DisplayRDSServiceName() +/// Update the text +void DisplayRDSText(char *name) +{ + Serial.print("RDS Text:"); + Serial.println(name); +} // DisplayRDSText() + +/// Update the Date/Time +void DisplayRDSTime(uint8_t hr, uint8_t mnt, uint32_t mjd, int8_t offset) +{ + Serial.print(" RDS Time: "); + if (hr < 10) + Serial.print('0'); + Serial.print(hr); + Serial.print(':'); + if (mnt < 10) + Serial.print('0'); + Serial.print(mnt); + Serial.print(" Offset: "); + Serial.print(offset); + + getMJDInfo(mjd, &mjd_info); + Serial.print(" Month: "); + Serial.print(mjd_info.month); + Serial.print(" Day: "); + Serial.print(mjd_info.day); + Serial.print(" Year: "); + Serial.println(mjd_info.year); +} // DisplayRDSTime() + + +void getMJDInfo(uint32_t mjd, MJD_INFO *mjdInfo) +{ + int _year = (int)((mjd - 15078.2) / 365.25); + int _month = (int)((mjd - 14956.1 - (int)(_year * 365.25)) / 30.6001); + int _day = (int)(mjd - 14956 - (int)(_year * 365.25) - (int)(_month * 30.6001)); + int k = (_month == 14 || _month == 15) ? 1 : 0; + + _year = _year + k + 1900; + _month = _month - 1 - k * 12; + + long WD = (long)((mjd + 2) % 7) + 1; //modulo 7 | Day of the Week + + mjdInfo->month = _month; + mjdInfo->day = _day; + mjdInfo->year = _year; +} // - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -216,7 +271,7 @@ void setup() { Serial.print("Radio..."); delay(500); - // Initialize the Radio + // Initialize the Radio radio.init(); // Enable information to the Serial port @@ -237,7 +292,10 @@ void setup() { // setup the information chain for RDS data. radio.attachReceiveRDS(RDS_process); - rds.attachServicenNameCallback(DisplayServiceName); + rds.attachServicenNameCallback(DisplayRDSServiceName); + rds.attachTextCallback(DisplayRDSText); + rds.attachTimeCallback(DisplayRDSTime); + runSerialCommand('?', 0); } // Setup @@ -298,7 +356,7 @@ void loop() { lastf = f; } // if nextFreqTime = now + 400; - } // if + } // if } // loop diff --git a/src/RDSParser.cpp b/src/RDSParser.cpp old mode 100644 new mode 100755 index 30cd688..6e25f14 --- a/src/RDSParser.cpp +++ b/src/RDSParser.cpp @@ -18,12 +18,14 @@ #define DEBUG_FUNC0(fn) { Serial.print(fn); Serial.println("()"); } /// Setup the RDS object and initialize private variables to 0. -RDSParser::RDSParser() { +RDSParser::RDSParser() +{ memset(this, 0, sizeof(RDSParser)); } // RDSParser() -void RDSParser::init() { +void RDSParser::init() +{ strcpy(_PSName1, "--------"); strcpy(_PSName2, _PSName1); strcpy(programServiceName, " "); @@ -56,29 +58,35 @@ void RDSParser::processData(uint16_t block1, uint16_t block2, uint16_t block3, u char c1, c2; char *p; - uint16_t mins; ///< RDS time in minutes - uint8_t off; ///< RDS time offset and sign + uint8_t hour; // RDS time in minutes + uint8_t mins; // RDS time in minutes + int8_t off; // RDS time offset and sign + uint32_t MJD; // Modified Julian Day // Serial.print('('); Serial.print(block1, HEX); Serial.print(' '); Serial.print(block2, HEX); Serial.print(' '); Serial.print(block3, HEX); Serial.print(' '); Serial.println(block4, HEX); - if (block1 == 0) { + if (block1 == 0) + { // reset all the RDS info. init(); // Send out empty data - if (_sendServiceName) _sendServiceName(programServiceName); - if (_sendText) _sendText(""); + if (_sendServiceName) + _sendServiceName(programServiceName); + if (_sendText) + _sendText(""); return; - } // if + } // analyzing Block 2 rdsGroupType = 0x0A | ((block2 & 0xF000) >> 8) | ((block2 & 0x0800) >> 11); rdsTP = (block2 & 0x0400); rdsPTY = (block2 & 0x0400); - switch (rdsGroupType) { + switch (rdsGroupType) + { case 0x0A: case 0x0B: - // The data received is part of the Service Station Name + // The data received is part of the Service Station Name idx = 2 * (block2 & 0x0003); // new data is 2 chars from block 4 @@ -88,28 +96,32 @@ void RDSParser::processData(uint16_t block1, uint16_t block2, uint16_t block3, u // check that the data was received successfully twice // before publishing the station name - if ((_PSName1[idx] == c1) && (_PSName1[idx + 1] == c2)) { + if ((_PSName1[idx] == c1) && (_PSName1[idx + 1] == c2)) + { // retrieved the text a second time: store to _PSName2 _PSName2[idx] = c1; _PSName2[idx + 1] = c2; _PSName2[8] = '\0'; - if ((idx == 6) && strcmp(_PSName1, _PSName2) == 0) { - if (strcmp(_PSName2, programServiceName) != 0) { + if ((idx == 6) && strcmp(_PSName1, _PSName2) == 0) + { + if (strcmp(_PSName2, programServiceName) != 0) + { // publish station name strcpy(programServiceName, _PSName2); if (_sendServiceName) _sendServiceName(programServiceName); - } // if - } // if - } // if + } + } + } - if ((_PSName1[idx] != c1) || (_PSName1[idx + 1] != c2)) { + if ((_PSName1[idx] != c1) || (_PSName1[idx + 1] != c2)) + { _PSName1[idx] = c1; _PSName1[idx + 1] = c2; _PSName1[8] = '\0'; // Serial.println(_PSName1); - } // if + } break; case 0x2A: @@ -117,51 +129,61 @@ void RDSParser::processData(uint16_t block1, uint16_t block2, uint16_t block3, u _textAB = (block2 & 0x0010); idx = 4 * (block2 & 0x000F); - if (idx < _lastTextIDX) { + if (idx < _lastTextIDX) + { // the existing text might be complete because the index is starting at the beginning again. - // now send it to the possible listener. - if (_sendText) + // send text if it's different than last sent. + if ((_sendText) && (strncmp(_lastRDSText, _RDSText, sizeof(_RDSText)) != 0)) + { + memcpy(_lastRDSText, _RDSText, sizeof(_RDSText)); _sendText(_RDSText); } + } _lastTextIDX = idx; - if (_textAB != _last_textAB) { + if (_textAB != _last_textAB) + { // when this bit is toggled the whole buffer should be cleared. _last_textAB = _textAB; memset(_RDSText, 0, sizeof(_RDSText)); // Serial.println("T>CLEAR"); - } // if - + } // new data is 2 chars from block 3 - _RDSText[idx] = (block3 >> 8); idx++; - _RDSText[idx] = (block3 & 0x00FF); idx++; + _RDSText[idx] = (block3 >> 8); + idx++; + _RDSText[idx] = (block3 & 0x00FF); + idx++; // new data is 2 chars from block 4 - _RDSText[idx] = (block4 >> 8); idx++; - _RDSText[idx] = (block4 & 0x00FF); idx++; + _RDSText[idx] = (block4 >> 8); + idx++; + _RDSText[idx] = (block4 & 0x00FF); + idx++; - // Serial.print(' '); Serial.println(_RDSText); - // Serial.print("T>"); Serial.println(_RDSText); break; case 0x4A: // Clock time and date - off = (block4)& 0x3F; // 6 bits + off = (30 * (((block4) & 0x3F) & 0x1F)) / 60; mins = (block4 >> 6) & 0x3F; // 6 bits - mins += 60 * (((block3 & 0x0001) << 4) | ((block4 >> 12) & 0x0F)); + hour = (((block3 & 0x0001) << 4) | ((block4 >> 12) & 0x0F)); + + MJD = (block3 >> 1); //shift to the right since Bit0 is not relevant + MJD = (MJD | 0x4000) | ((block2 & 0x1) << 14); //Bit 0 of block B becomes bit15 in MJD + MJD = (MJD | 0x8000) | ((block2 & 0x2) << 15); //Bit 1 of block B becomes bit 16 in MJD // adjust offset - if (off & 0x20) { - mins -= 30 * (off & 0x1F); - } else { - mins += 30 * (off & 0x1F); + if (((block4) & 0x3F) & 0x20) + { + off *= -1; } - if ((_sendTime) && (mins != _lastRDSMinutes)) { + if ((_sendTime) && (mins != _lastRDSMinutes)) + { _lastRDSMinutes = mins; - _sendTime(mins / 60, mins % 60); - } // if + _sendTime(hour, mins, MJD, off); + } break; case 0x6A: diff --git a/src/RDSParser.h b/src/RDSParser.h old mode 100644 new mode 100755 index 4180e41..1637749 --- a/src/RDSParser.h +++ b/src/RDSParser.h @@ -6,7 +6,7 @@ /// \copyright Copyright (c) 2014 by Matthias Hertel.\n /// This work is licensed under a BSD style license.\n /// See http://www.mathertel.de/License.aspx -/// +/// /// \details /// /// More documentation and source code is available at http://www.mathertel.de/Arduino @@ -16,7 +16,7 @@ /// * 01.09.2014 created and RDS sender name working. /// * 01.11.2014 RDS time added. /// * 27.03.2015 Reset RDS data by sending a 0 in blockA in the case the frequency changes. -/// +/// #ifndef __RDSPARSER_H__ @@ -24,11 +24,11 @@ #include -/// callback function for passing a ServicenName +/// callback function for passing a ServicenName extern "C" { typedef void(*receiveServicenNameFunction)(char *name); typedef void(*receiveTextFunction)(char *name); - typedef void(*receiveTimeFunction)(uint8_t hour, uint8_t minute); + typedef void(*receiveTimeFunction)(uint8_t hour, uint8_t minute, uint32_t MJD, int8_t offset); } @@ -64,7 +64,7 @@ class RDSParser uint16_t _lastRDSMinutes; ///< last RDS time send to callback. - char _RDSText[64 + 2]; + char _RDSText[64 + 2], _lastRDSText[64 + 2]; }; //RDSParser