Library to decode MSF time signal.

Files at this revision

API Documentation at this revision

Comitter:
dswood
Date:
Fri Jan 07 12:12:25 2022 +0000
Commit message:
A simple library to decode MSF time signal. Probably useful for DSF

Changed in this revision

MSF_Time.cpp Show annotated file Show diff for this revision Revisions of this file
MSF_Time.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MSF_Time.cpp	Fri Jan 07 12:12:25 2022 +0000
@@ -0,0 +1,746 @@
+/*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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MSF_Time.h	Fri Jan 07 12:12:25 2022 +0000
@@ -0,0 +1,75 @@
+/*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
+*/
+
+
+
+#include "mbed.h"
+class MSF_Time
+{
+public:
+/* Start MSF_Time with this function
+InputPin is the data coming from your reciever
+ Polarity is 0 if your receiver output is high for no carrier
+ polarity is 1 to invert this logic. */
+ 
+ 
+MSF_Time(PinName InputPin, int polarity,int OffsetTuning =48000);
+
+bool Valid(); // Is the time valid
+time_t Read();
+
+protected:
+struct MSF_Data {
+    int BCDYear;
+    int BCDMonth;
+    int DayOfWeek;
+    int BCDTime;
+    int SyncByte;  //This is sent and allows you to detect leap seconds
+    int DUT;
+    int BST;
+};
+
+struct MSF_Data MyData;    
+struct tm Received_Time; // Normal data coming in
+time_t Received_timestamp;  //Data converted to timestamp
+unsigned int Time_Data_Duration; //Pulse length - The minute marker is 500ms
+bool Time_Data_Sync;  // True when a 500ms pulse is detected denoting the start of a minute
+Ticker Time_Data_Ticker;  // A 50ms clock used to clock in data
+unsigned int Time_Data_Count;//  counts the 50ms for clocking in the data
+void Time_Data_Strobe(); // When the ticker ticks do this
+void Falling();
+void Rising();
+bool DataValid;
+Timeout offset; // used to fine tune the seconds 50ms equals zero offset
+InterruptIn Time_Data;
+DigitalIn MyInput;
+int Polarity;
+int OffsetTuning;
+Timer Time_Data_timer;
+void LogicOne();
+void LogicZero();
+int ParityCheck(unsigned int CheckMe);
+void ProcessData();
+void IncrementSeconds();
+void IncrementSecondsNow();
+//int const OffsetTuning=48000; //in microseconds
+bool debug;  //turn on off debugging noise
+bool DV;
+
+};
\ No newline at end of file