Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Date and time with MJD and example usage #38

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 72 additions & 14 deletions examples/SerialRadio/SerialRadio.ino
100644 → 100755
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -76,15 +76,23 @@ 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.


/// get a RDS parser
RDSParser rds;

/// Modified Julian Day from RDS Time
typedef struct MJD_INFO {
int month;
int day;
int year;
};

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MDJ structures and functions should be moved into RDSParser to be available is all sketches.

MJD_INFO mjd_info;

/// State definition for this radio implementation.
enum RADIO_STATE {
Expand All @@ -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];
Expand All @@ -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);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid floating-point arithmetic. I hope you find a pure integer based solution.

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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WD is calculated by not used. can be removed or commented.


mjdInfo->month = _month;
mjdInfo->day = _day;
mjdInfo->year = _year;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - -

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -298,7 +356,7 @@ void loop() {
lastf = f;
} // if
nextFreqTime = now + 400;
} // if
} // if

} // loop

Expand Down
100 changes: 61 additions & 39 deletions src/RDSParser.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and in other places re re-formatting should be reversed to focus on the changes.

memset(this, 0, sizeof(RDSParser));
} // RDSParser()


void RDSParser::init() {
void RDSParser::init()
{
strcpy(_PSName1, "--------");
strcpy(_PSName2, _PSName1);
strcpy(programServiceName, " ");
Expand Down Expand Up @@ -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
Expand All @@ -88,80 +96,94 @@ 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:
// The data received is part of the RDS Text.
_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:
Expand Down
10 changes: 5 additions & 5 deletions src/RDSParser.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -16,19 +16,19 @@
/// * 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__
#define __RDSPARSER_H__

#include <Arduino.h>

/// 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);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pleas add a new callback function to not break compatibility.

}


Expand Down Expand Up @@ -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

Expand Down