Library to decode MSF time signal.
MSF_Time.cpp
- Committer:
- dswood
- Date:
- 2022-01-07
- Revision:
- 0:340305453f64
File content as of revision 0:340305453f64:
/*This library will decode an MSF signal on a digital input pin and turn it
into a timestamp.
Copyright (C) 2017 Duncan Wood
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MSF_Time_h
#define MSF_Time_h
#include "mbed.h"
#include "MSF_Time.h"
MSF_Time::MSF_Time(PinName InputPin, int polarity, int OffsetTuning)
: Time_Data(InputPin), Polarity(polarity), OffsetTuning(OffsetTuning),
MyInput(InputPin)
{
DataValid=false;
Time_Data_Count=0;
Time_Data_Duration=0x0000;
Time_Data.fall(this, &MSF_Time::Falling);
Time_Data.rise(this, &MSF_Time::Rising);
Received_timestamp=0; //set time to zero until we can set it properly
MyData.BCDMonth=0;
MyData.BCDTime=0;
MyData.BCDYear=0;
MyData.SyncByte=0;
MyData.DayOfWeek=0;
MyData.BST=0;
MyData.DUT=0;
}
void MSF_Time::Rising()
{
if (Polarity==0) {
LogicOne();
} else {
LogicZero();
}
}
void MSF_Time::LogicOne() //When there is no carrier (pulse every second)
{
Time_Data_timer.reset();
Time_Data_timer.start();
}
void MSF_Time::LogicZero() // When carrier is present (most of the time)
{
Time_Data_timer.stop();
Time_Data_Duration=Time_Data_timer.read_us();
// Test for the 500ms minute sync pulse
if (Time_Data_Duration > 450000 && Time_Data_Duration < 550000 ) { // +/-50ms for now
Received_Time.tm_sec=0; //set time to zero until we can set it properly
Time_Data_Count=0;
MyData.BCDMonth=0;
MyData.BCDTime=0;
MyData.BCDYear=0;
MyData.SyncByte=0;
MyData.DayOfWeek=0;
Time_Data_Sync=true;
Time_Data_Ticker.attach(this, &MSF_Time::Time_Data_Strobe,0.05); // start a timer to read data
}
}
void MSF_Time::Falling()
{
if (Polarity==0) {
LogicZero();
} else {
LogicOne();
}
}
void MSF_Time::IncrementSeconds()
{
// called 50ms ish before the second. Add delay of 50ms ish.
offset.attach_us(this, &MSF_Time::IncrementSecondsNow,OffsetTuning);
}
void MSF_Time::IncrementSecondsNow()
{
Received_timestamp++;
if (DV) { //this is the signal to set time now at 00 seconds
DV=false;
Received_Time.tm_sec=0;
Received_timestamp=mktime(&Received_Time);
if (Received_timestamp != -1 ) {//0x80000001
DataValid=true;
}
}
}
void MSF_Time::Time_Data_Strobe()
{
Time_Data_Count++;
switch(Time_Data_Count) {
case 1:
break;
case 9: //zero seconds
IncrementSeconds();
break;
//case 13://01A
//case 15://01B DUT1+
//break;
case 29:// Incerment seconds
IncrementSeconds();
break;
//case 33://02A
//case 35://02B DUT1+
//break;
case 49:
IncrementSeconds();
break;
//case 53://03A
//case 55://03B DUT1+
//break;
case 69:
IncrementSeconds();
break;
//case 73://04A
//case 75://04B DUT1+
case 89:
IncrementSeconds();
break;
//case 93://05A
//case 95://05B DUT1+
case 109:
IncrementSeconds();
break;
//case 113://06A
//case 115://06B DUT1+
case 129:
IncrementSeconds();
break;
//case 133://07A
//case 135://07B DUT1+
case 149:
IncrementSeconds();
break;
//case 153://08A
//case 155://08B DUT1+
case 169:
IncrementSeconds();
break;
//case 173://09A
//case 175://09B DUT1-
case 189:
IncrementSeconds();
break;
//case 193://10A
//case 195://10B DUT1-
case 209:
IncrementSeconds();
break;
//case 213://11A
//case 215://11B DUT1-
case 229:
IncrementSeconds();
break;
//case 233://12A
//case 235://12B DUT1-
case 249:
IncrementSeconds();
break;
//case 253://13A
//case 255://13B DUT1-
case 269:
IncrementSeconds();
break;
//case 273://14A
//case 275://14B DUT1-
case 289:
IncrementSeconds();
break;
//case 293://15A
//case 295://15B DUT1-
case 309:
IncrementSeconds();
break;
case 313://16A
MyData.BCDYear+= MyInput.read()^Polarity;
//leap second
break;
//case 315://16B DUT1-
case 329:
IncrementSeconds();
break;
case 333://17A Year 80
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
break;
//case 335://17B
case 349:
IncrementSeconds();
break;
case 353://18A Year 40
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
break;
//case 355://18B
case 369:
IncrementSeconds();
break;
case 373://19A Year 20
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
break;
//case 375://19B
case 389:
IncrementSeconds();
break;
case 393://20A Year 10
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
break;
//case 395://20B
case 409:
IncrementSeconds();
break;
case 413://21A Year 8
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
break;
//case 415://21B
case 429:
IncrementSeconds();
break;
case 433://22A Year 4
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
break;
//case 435://22B
case 449:
IncrementSeconds();
break;
case 453://23A Year 2
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
break;
//case 455://23B
case 469:
IncrementSeconds();
break;
case 473://24A Year 1
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
MyData.BCDMonth+= MyInput.read()^Polarity;; //leap second minus
break;
//case 475://24B
case 489:
IncrementSeconds();
break;
case 493://25A Month 10
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity; //leap second
break;
//case 495://25B
case 509:
IncrementSeconds();
break;
case 513://26A Month 8
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
//case 515://26B
case 529:
IncrementSeconds();
break;
case 533://27A Month 4
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
//case 535://27B
case 549:
IncrementSeconds();
break;
case 553://28A Month 2
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
//case 555://28B
case 569:
IncrementSeconds();
break;
case 573://29A Month 1
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
//case 575://29B
case 589:
IncrementSeconds();
break;
case 593://30A Day of Month 20
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
//case 595://30B
case 609:
IncrementSeconds();
break;
case 613://31A Day of Month 10
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
//case 615://31B
case 629:
IncrementSeconds();
break;
case 633://32A Day of Month 8
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
//case 635://32B
case 649:
IncrementSeconds();
break;
case 653://33A Day of Month 4
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
//case 655://33B
case 669:
IncrementSeconds();
break;
case 673://34A Day of Month 2
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
//case 675://34B
case 689:
IncrementSeconds();
break;
case 693://35A Day of Month 1
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
MyData.DayOfWeek+= MyInput.read()^Polarity;
break;
//case 695://35B
case 709:
IncrementSeconds();
break;
case 713://36A Day of Week 4
MyData.DayOfWeek=MyData.DayOfWeek <<1;
MyData.DayOfWeek+= MyInput.read()^Polarity;
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
// case 715://36B
case 729:
IncrementSeconds();
break;
case 733://37A Day of Week 2
MyData.DayOfWeek=MyData.DayOfWeek <<1;
MyData.DayOfWeek+= MyInput.read()^Polarity;
break;
//case 735://37B
case 749:
IncrementSeconds();
break;
case 753://38A Day of Week 1
MyData.DayOfWeek=MyData.DayOfWeek <<1;
MyData.DayOfWeek+= MyInput.read()^Polarity;
MyData.BCDTime+= MyInput.read()^Polarity; //leap second
break;
//case 755://38B
case 769:
IncrementSeconds();
break;
case 773://39A Hour 20
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
MyData.DayOfWeek=MyData.DayOfWeek <<1;
MyData.DayOfWeek+= MyInput.read()^Polarity; //leap second
break;
//case 775://39B
case 789:
IncrementSeconds();
break;
case 793://40A Hour 10
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 795://40B
case 809:
IncrementSeconds();
break;
case 813://41A Hour 8
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 815://41B
case 829:
IncrementSeconds();
break;
case 833://42A Hour 4
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 835://42B
case 849:
IncrementSeconds();
break;
case 853://43A Hour 2
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 855://43B
case 869:
IncrementSeconds();
break;
case 873://44A Hour 1
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 875://44B
case 889:
IncrementSeconds();
break;
case 893://45A Minute 40
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 895://45B
case 909:
IncrementSeconds();
break;
case 913://46A Minute 20
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 915://46B
case 929:
IncrementSeconds();
break;
case 933://47A Minute 10
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 935://47B
case 949:
IncrementSeconds();
break;
case 953://48A Minute 8
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 955://48B
case 969:
IncrementSeconds();
break;
case 973://49A Minute 4
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 975://49B
case 989:
IncrementSeconds();
break;
case 993://50A Minute 2
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
//case 995://50B
case 1009:
IncrementSeconds();
break;
case 1013://51A Minute 1
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
MyData.SyncByte+= MyInput.read()^Polarity; // Or is it a leap second
break;
//case 1015://51B
case 1029:
IncrementSeconds();
break;
case 1033://52A set to 0
MyData.SyncByte=MyData.SyncByte <<1;
MyData.SyncByte+= MyInput.read()^Polarity;
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity; //leap second
break;
//case 1035://52B
case 1049:
IncrementSeconds();
break;
case 1053://53A set to 1
MyData.SyncByte=MyData.SyncByte <<1;
MyData.SyncByte+= MyInput.read()^Polarity;
break;
case 1055://53B Change of summertime soon
// Fortunately leap seconds are never added in spring or autumn
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
break;
case 1069:
IncrementSeconds();
break;
case 1073://54A set to 1
MyData.SyncByte=MyData.SyncByte <<1;
MyData.SyncByte+= MyInput.read()^Polarity;
break;
case 1075://54B Year Parity
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
break;
case 1089:
IncrementSeconds();
break;
case 1093://55A set to 1
MyData.SyncByte=MyData.SyncByte <<1;
MyData.SyncByte+= MyInput.read()^Polarity;
break;
case 1095://55B Month Parity
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
MyData.BCDYear=MyData.BCDYear << 1;
MyData.BCDYear+= MyInput.read()^Polarity;
MyData.DayOfWeek=MyData.DayOfWeek <<1;
MyData.DayOfWeek+= MyInput.read()^Polarity;
break;
case 1109:
IncrementSeconds();
break;
case 1113://56A set to 1
MyData.SyncByte=MyData.SyncByte <<1;
MyData.SyncByte+= MyInput.read()^Polarity;
break;
case 1115://56B day of Week Parity
MyData.DayOfWeek=MyData.DayOfWeek <<1;
MyData.DayOfWeek+= MyInput.read()^Polarity;
MyData.BCDMonth=MyData.BCDMonth << 1;
MyData.BCDMonth+= MyInput.read()^Polarity;
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
break;
case 1129:
IncrementSeconds();
break;
case 1133://57A set to 1
MyData.SyncByte=MyData.SyncByte <<1;
MyData.SyncByte+= MyInput.read()^Polarity;
break;
case 1135://57B Time - hour minute parity
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
MyData.DayOfWeek=MyData.DayOfWeek <<1;
MyData.DayOfWeek+= MyInput.read()^Polarity;
break;
case 1149:
IncrementSeconds();
break;
case 1153://58A set to 1
MyData.SyncByte=MyData.SyncByte <<1;
MyData.SyncByte+= MyInput.read()^Polarity;
break;
case 1155://58B British Summertime
MyData.BCDTime=MyData.BCDTime << 1;
MyData.BCDTime+= MyInput.read()^Polarity;
MyData.BST=MyInput.read()^Polarity;
break;
case 1169:
IncrementSeconds();
ProcessData();// if success count will be stopped but increment will still happen
break;
case 1173://59A set to 0
MyData.SyncByte=MyData.SyncByte <<1;
MyData.SyncByte+= MyInput.read()^Polarity;
break;
// case 1175://59B
case 1189:
IncrementSeconds();
ProcessData();
break;
case 1193://60A
MyData.SyncByte=MyData.SyncByte <<1;
MyData.SyncByte+= MyInput.read()^Polarity; //
break;
// case 1195://60B
case 1209:
IncrementSeconds();
ProcessData();
// End stop
// On a leap second we should count extra but not dealing with it
// so for one minute time will be out by a second.
Time_Data_Ticker.detach();
Time_Data_Count=0; // Should stop this being called more than once
DataValid=false; //no data received
}
}
int MSF_Time::ParityCheck(unsigned int CheckMe) //0=even 1= odd naturally
{
// My parity is going to check 16 bit feel free to add more
// Stolen shamelessly from internet
//x ^= x >> 16;
//x ^= x >> 8;
//x ^= x >> 4;
//x ^= x >> 2;
//x ^= x >> 1;
//return (~x) & 1;
CheckMe^=CheckMe>>8;
CheckMe^=CheckMe>>4;
CheckMe^=CheckMe>>2;
CheckMe^=CheckMe>>1;
CheckMe&=1;// 1=odd 0=even
return CheckMe;
}
void MSF_Time::ProcessData()
{
DV=false;
int shift=0; // by how much to shift just to leave data
// Find sync
// sync data is 01111110
if ((MyData.SyncByte&0x0FF) == 0x07E) { // sync byte
/* There are 3 processdata calls. The ticker will be either
1155 or 1173 or 1193. If it is on time or late, extra data will
have been collected. We shall get rid.*/
} else {
if (Time_Data_Count==1193) {
//pc.printf("last chance of sync failed - data not valid");
DataValid=false;
}
return;
}
if (Time_Data_Count==1169) { //leap second early
shift=2;
}
if (Time_Data_Count==1189) {
shift=1;
}
if (Time_Data_Count==1209) {
shift=0;
}
Time_Data_Ticker.detach();
Time_Data_Count=0; // Should stop this being called more than once
MyData.BCDYear>>=shift;
MyData.BCDMonth>>=shift;
MyData.DayOfWeek>>=shift;
MyData.BCDTime>>=shift;
MyData.BCDYear&=0x7F9 ; //8 bits +2 rubbish + parity
MyData.BCDMonth&=0x3FF9; // 11 bits +2 rubbish + parity
MyData.DayOfWeek&=0x039 ; //3 bits +2 rubbish + parity
MyData.BCDTime&=0xFFF9; // 13bits +2 rubbish + parity
if (ParityCheck(MyData.BCDYear) &&
ParityCheck(MyData.BCDMonth) &&
ParityCheck(MyData.DayOfWeek) &&
ParityCheck(MyData.BCDTime) ) {
// Parity ok - remove parity bits
MyData.BCDYear>>=3;
MyData.BCDMonth>>=3;
MyData.DayOfWeek>>=3;
MyData.BCDTime>>=3;
DV=true;
} else {
DataValid=false; //sync but parity fail
return;
}
//Convert BCD to binary
// pc.printf("Year Month DOW Time\n\r");
//pc.printf("%x %x %x %x\n\r",MyData.BCDYear,MyData.BCDMonth,MyData.DayOfWeek,MyData.BCDTime);
if (DV) {
Received_Time.tm_year=100+(MyData.BCDYear & 0x0F)+(10*((MyData.BCDYear>>4) & 0x01)) ; //years _since_ 1900
Received_Time.tm_mon=((MyData.BCDMonth>>6) & 0x0F)+(10*((MyData.BCDMonth>>10) & 0x01))-1;
Received_Time.tm_mday=(MyData.BCDMonth & 0x0F)+(10*((MyData.BCDMonth>>4) & 0x03)) ;
Received_Time.tm_hour=((MyData.BCDTime>>7)& 0x0F)+(10*((MyData.BCDTime>>11) & 0x03));
Received_Time.tm_min=(MyData.BCDTime&0x0F)+(10*((MyData.BCDTime>>4) & 0x07));
Received_Time.tm_wday = (MyData.DayOfWeek&0x07);
Received_Time.tm_sec=0;
}
}
bool MSF_Time::Valid()
{
//if (DataValid) pc.printf("Data Valid\n\r");
return DataValid;
}
time_t MSF_Time::Read()
{
// pc.printf("Received ts %s\n\r",ctime(&Received_timestamp));
return Received_timestamp;
}
#endif