#define BIT_TIME 150    // this value should be between 100 and 200, it decides between 0 and 1
#define MINUTE_UP 1400  // the minute is up
#define DCF_INPUT 10    // DCF77 input pin
int8_t VALUES[] = {1, 2, 4, 8, 10, 20, 40, 80};
const char *WEEKDAYS[] = {"--", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"};
const char *CEST[] = {"CET", "CEST"};
unsigned long milli = 0;  // global variables
uint8_t cest = 0;
uint8_t minute = 0;
uint8_t hour = 0;
uint8_t day = 0;
uint8_t weekday = 0;
uint8_t month = 0;
uint8_t year = 0;
uint8_t position = 0;
uint8_t parity = 0;  // even parity in the time signal
uint8_t dcfPIN = 0;  // status of the DCF77 input pin
void setup()
{
   Serial.begin(115200); // init serial interface
   
   while (!Serial)
      delay(1);
   
   pinMode(LED_BUILTIN, OUTPUT);
   pinMode(DCF_INPUT, INPUT);
   
   Serial.println("Start...DCF77");  // 'Hello world'
}
void loop()
{ 
   int _dcfPIN = digitalRead(DCF_INPUT); // read the DCF77 input
   
   if (dcfPIN != _dcfPIN) 
   {  // the input has changed
      dcfPIN = _dcfPIN;          // remember the value
      digitalWrite(LED_BUILTIN, dcfPIN);  // update the onboard LED
      
      unsigned long _milli = millis();    // increasing millisecond counter 
      unsigned long len = _milli - milli; // calculates the pulse length
      milli = _milli;                     // remember the value
       
      if (dcfPIN == 0)  // this means that the signal was high and is now low
      {
         // Serial.println(len);  // optional to see the bit length
         
         if  (len > BIT_TIME)  // zero or one ?
         {                     // one !
            parity += 1;
            if (position >= 21 && position <= 27)       // minute
               minute += VALUES[position - 21];
            else if (position >= 29 && position <= 34)   // hour
               hour += VALUES[position - 29];
            else if (position >= 36 && position <= 41)  // day
               day += VALUES[position - 36];
            else if (position >= 42 && position <= 44)  // weekday
               weekday += VALUES[position - 42];
            else if (position >= 45 && position <= 49)  // month
               month += VALUES[position - 45];
            else if (position >= 50 && position <= 57)  // year
               year += VALUES[position - 50];           // only the year, not the century   
            if (position == 17)
               cest = 1;               // Central European Summer Time
            else if (position == 18)
            {
               if (cest == 1)          // Central European Time
                  position = 0;        // Error: sets the position to 0, making the time information invalid
            }
            else if (position == 20)   // start of encoded time, always 1
               parity = 0;             // reset parity for the following bits
            else if (position == 28 || position == 35 || position == 58)
            {
               if ((parity % 2) != 0)  // even parity ?
                  position = 0;        // Error: sets the position to 0, making the time information invalid
                  
               parity = 0;             // reset parity for the following bits
            }
         }
         else  // zero
         {
            if (position == 28 || position == 35 || position == 58)
            {
                if ((parity % 2) != 0) // even parity ?
                    position = 0;      // Error: sets the position to 0, making the time information invalid
                
                parity = 0;            // reset parity for the following bits
            }
         }
   
         Serial.print("Bit: "); Serial.println(position);  // optional
         
         // char buf[100];
         // sprintf(buf, "Timestamp: %d-%02d-%02d %02d:%02d %s %s", (year + 2000), month, day, hour, minute, 
         //                                                         WEEKDAYS[weekday], CEST[cest]);
         // Serial.println(buf);
         // enable the lines above to see how the date and time evolve
         position += 1; // increment the bit counter
      }
      else 
      {
         if (len > MINUTE_UP)
         {
            // the minute is up, the parity bit does not allow error correction, 
            // so some additional checks are performed
            if (position == 59 && (minute >= 0 && minute <= 59 || hour >= 0 && hour <= 23 || 
                                   day >= 1 && day <= 31 || weekday >= 1 && weekday <= 7 ||
                                   month >= 1 && month <= 12 || year >= 25))
            {
               char buf[100];
               sprintf(buf, "Timestamp: %d-%02d-%02d %02d:%02d %s %s", (year + 2000), month, day, hour, 
                        minute, WEEKDAYS[weekday], CEST[cest]);
               Serial.println(buf);
            }
            else
               Serial.println("No valid timestamp");
               
            cest = 0;  // reset everything, preparing for the next minute
            minute = 0;
            hour = 0;
            day = 0;
            weekday = 0;
            month = 0;
            year = 0;
            position = 0;
            parity = 0;
         }
      }
   }
   
   delay(1);
}