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