From subsecret
Jump to: navigation, search

Video: https://www.youtube.com/watch?v=HxVnWieD0pE

Components used:

Arduino program:

#include <TimeLib.h>
#include <LiquidCrystal.h>

#define READPIN 2
#define btnDOWN   13

#define ZERO_DUR_START  83L
#define ZERO_DUR_END  136L
#define ONE_DUR_START  178L
#define ONE_DUR_END  231L
#define SIGNALGAP_DUR_START 1900L
#define SIGNALGAP_DUR_END  2100L
#define DEBUG false

int decodeMultipliers[] =  {1, 1, 2, 4, 8, 10, 20, 40, 1, 1, 2, \
                            4, 8, 10, 20, 1, 1, 2, 4, 8, 10, 20, 1, 2, 4, 1, 2, 4, \
                            8, 10, 1, 2, 4, 8, 10, 20, 40, 80, 1, 1
                           };

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

boolean dcf_received_date = false;
boolean dcf_received_time = false;

int last_dcf_hours = -1;
int last_dcf_mins = -1;
int last_dcf_day = -1;
int last_dcf_month = -1;
int last_dcf_year = -1;
int last_dcf_received = millis();

void dcfTimeDateReceived(int dcf_hours, int dcf_mins, int dcf_day, int dcf_month, int dcf_year) {
  Serial.print("Complete: ");
  Serial.print(dcf_hours);
  Serial.print(":");
  Serial.print(dcf_mins);
  Serial.print(" ");
  Serial.print(dcf_day);
  Serial.print("-");
  Serial.print(dcf_month);
  Serial.print("-");
  Serial.print(dcf_year);
  Serial.println();

  setTime(dcf_hours, dcf_mins, 0, dcf_day, dcf_month, dcf_year);
  dcf_received_date = true;
  dcf_received_time = true;

}

void dcfIncompleteTimeDateReceived(int dcf_hours, int dcf_mins, int dcf_day, int dcf_month, int dcf_year) {
  Serial.print("Incomplete: ");
  Serial.print(dcf_hours);
  Serial.print(":");
  Serial.print(dcf_mins);
  Serial.print(" ");
  Serial.print(dcf_day);
  Serial.print("-");
  Serial.print(dcf_month);
  Serial.print("-");
  Serial.print(dcf_year);
  Serial.println();

}

void dcfOnlyTimeReceived(int dcf_hours, int dcf_mins) {
  Serial.print("Time: ");
  Serial.print(dcf_hours);
  Serial.print(":");
  Serial.print(dcf_mins);
  Serial.println();
  dcf_received_time = true;
}


void dcfOnlyDateReceived(int dcf_day, int dcf_month, int dcf_year) {
  Serial.print("Date: ");
  Serial.print(dcf_day);
  Serial.print("-");
  Serial.print(dcf_month);
  Serial.print("-");
  Serial.print(dcf_year);
  Serial.println();
  dcf_received_date = true;
}

void setup() {
  Serial.begin(115200);
  pinMode(READPIN, INPUT_PULLUP);
  lcd.begin(16, 2);

}

unsigned long lastRef = millis();
boolean showTime = true;
void printTimeToLCD() {
  //450 down
  unsigned long elap = millis() - lastRef;
  if (elap > 600) {

   int val = analogRead(0);
    if (val >= 430 && val <= 495) {
      showTime = !showTime;
    }
    lcd.clear();
 
    

    if (showTime) {
      if (dcf_received_time && dcf_received_date) {
        lcd.setCursor(0, 0);
        twoDigitPrint(hour());
        lcd.print(":");
        twoDigitPrint(minute());
        lcd.print(":");
        twoDigitPrint(second());
        lcd.setCursor(0, 1);

        lcd.print(day());
        lcd.print("-");
        lcd.print(month());
        lcd.print("-");
        lcd.print(year());

      } else {
        lcd.setCursor(0, 0);
        lcd.print("Waiting ");
        lcd.print(millis() / 1000);
        lcd.print(" sec");
      }
    } else {
      lcd.setCursor(0, 0);
      lcd.print("DCF ");
      twoDigitPrint(last_dcf_hours);
      lcd.print(":");
      twoDigitPrint(last_dcf_mins);
      lcd.print(" (");
      lcd.print(((millis() - last_dcf_received) / 1000));
      lcd.print(")");
      lcd.setCursor(0, 1);

      oneDigitPrint(last_dcf_day);
      lcd.print("-");
      oneDigitPrint(last_dcf_month);
      lcd.print("-");
      oneDigitPrint(last_dcf_year);
    }
    lastRef = millis();
  }

}
void oneDigitPrint(int num) {
  if (num == -1) {
    lcd.print("??");
    return;
  }
  lcd.print(num);
}
void twoDigitPrint(int num) {
  if (num == -1) {
    lcd.print("??");
    return;
  }
  if (num <= 9) {
    lcd.print("0");
  }
  lcd.print(num);
}


void loop() {
  unsigned long lastStartTime, signalGap, startTime, stopTime, elapsed, tmp;
  unsigned long sTimes[200];
  int bits[200];
  int i = 0;
  lastStartTime = 0;
  while (true) {
    startTime = millis();
    stopTime = startTime;
    printTimeToLCD();
    boolean active = digitalRead(READPIN);
    if (active) {
      while (true)  {
        active = digitalRead(READPIN);
        if (active) {
          stopTime = millis();
        }
        else  {
          if (millis() < stopTime) {
            //arduino time wrap-around, break loop
            break;
          }
          tmp = millis() - stopTime;
          if ( tmp > 2L) {
            break;
          }
        }
      }
      elapsed = stopTime - startTime;

      signalGap = startTime - lastStartTime;

      lastStartTime = startTime;
      if ((elapsed >= ZERO_DUR_START && elapsed <= ZERO_DUR_END) || (elapsed >= ONE_DUR_START && elapsed <= ONE_DUR_END)) {
        if (DEBUG) {
          debugPrint("ACK: ", startTime, elapsed);
        }
        sTimes[i % 100] = startTime;
        if (elapsed >= ZERO_DUR_START && elapsed <= ZERO_DUR_END) {
          bits[i % 100] = 0;
        }
        if ( elapsed >= ONE_DUR_START && elapsed <= ONE_DUR_END) {
          bits[i % 100] = 1;
        }
        i++;
        if (i == 200) {
          i = 100;
        }

      } else {
        if (DEBUG) {
          debugPrint("REJ: ", startTime, elapsed);
        }
      }
      if (signalGap >= SIGNALGAP_DUR_START && signalGap <= SIGNALGAP_DUR_END) {
        if (DEBUG) {
          debugPrint("GAP: ", startTime, elapsed);
        }
        analyseSignal(i, bits, sTimes);
      }

    }


  }
}
void analyseSignal(int i, int* bits, unsigned long* sTimes) {
  if (i < 40) {
    return;
  }
  int index = i - 1;
  int signalArr[40];
  int k = 39;
  for (int i = 0; i < 40; i++) {
    signalArr[i] = -1;
  }
  unsigned long startTime = sTimes[index % 100] - 1000L;
  index--;
  int tries = 0;
  while (k >= 0 && tries < 100) {
    tries++;
    unsigned long currTime = sTimes[index % 100];
    int bitVal = bits[(index + 1) % 100 ];

    for (int skip = 0; skip <= 4; skip++) {
      long tDiff = ((long)startTime) - ((long)currTime) - 1000L - skip * 1000L;
      if (tDiff < 0L) {
        tDiff = -tDiff;
      }
      if (tDiff < 20L + 10L * skip) {
        startTime = currTime;
        if (skip > 0) {
          for (int a = 0; a < skip; a++) {
            k--;
          }
        }
        if (k >= 0) {
          signalArr[k] = bitVal;
        }
        k--;
        break;
      }
    }


    index--;
  }
  boolean correctTimeStart = (signalArr[0] == 1);
  boolean parityMins = checkEvenParity(signalArr, 1, 8, 8);
  boolean parityHours = checkEvenParity(signalArr, 9, 15, 15);
  boolean parityDate = checkEvenParity(signalArr, 16, 38, 38);
  if (DEBUG) {
    debugSignal(signalArr, sTimes, bits, i);
  }

  for (int k = 0; k < 40; k++) {
    if (signalArr[k] != -1) {
      signalArr[k] = signalArr[k] * decodeMultipliers[k];
    }
  }

  int dcf_mins = getValue(signalArr, 1, 7);
  int dcf_hours = getValue(signalArr, 9, 14);
  int dcf_day = getValue(signalArr, 16, 21);
  int dcf_month = getValue(signalArr, 25, 29);
  int dcf_year =  getValue(signalArr, 30, 37);


  last_dcf_hours = dcf_hours;
  last_dcf_mins = dcf_mins;
  last_dcf_day = dcf_day;
  last_dcf_month = dcf_month;
  last_dcf_year = dcf_year;
  last_dcf_received = millis();

  if (correctTimeStart && parityMins && parityHours && parityDate) {
    dcfTimeDateReceived(dcf_hours, dcf_mins, dcf_day, dcf_month, dcf_year);
  }
  else if (correctTimeStart && parityMins && parityHours && !parityDate) {
    dcfOnlyTimeReceived(dcf_hours, dcf_mins);
    dcfIncompleteTimeDateReceived(dcf_hours, dcf_mins, dcf_day, dcf_month, dcf_year);
  } else if (parityDate) {
    dcfOnlyDateReceived(dcf_day, dcf_month, dcf_year);
    dcfIncompleteTimeDateReceived(dcf_hours, dcf_mins, dcf_day, dcf_month, dcf_year);
  }  else {
    dcfIncompleteTimeDateReceived(dcf_hours, dcf_mins, dcf_day, dcf_month, dcf_year);
  }

}

boolean checkEvenParity(int* arr, int startBit, int endBit, int parityBit) {
  int sum = 0;
  for (int k = startBit; k <= endBit; k++) {
    if (arr[k] != -1) {
      sum += arr[k];
    } else {
      sum = -1;
      break;
    }
  }
  int parity = arr[parityBit];
  if (sum == -1) {
    return false;
  }
  if (parity == -1) {
    return false;
  }
  if (sum % 2 == 0) {
    return true;
  }
  return false;

}
void debugPrint(String prefix, unsigned long time, unsigned long elapsed) {
  Serial.print(prefix);
  Serial.print(time);
  Serial.print(" - ");
  Serial.print(elapsed);
  Serial.println();
}

void debugSignal(int* arr, unsigned long* st, int* bt, int i) {
  Serial.println("RAW Data (2 lines)");
  for (int index = i - 40; index < i; index++) {
    Serial.print(st[index % 100]);
    Serial.print(",");
  }
  Serial.println();
  for (int index = i - 40; index < i; index++) {
    Serial.print(bt[index % 100]);
    Serial.print(",");
  }
  Serial.println();

  Serial.print("SIGNAL: ");
  for (int k = 0; k < 40; k++) {
    if (arr[k] == -1) {
      Serial.print("?");
    } else {
      Serial.print(arr[k]);
    }
    Serial.print(",");

  }
  Serial.println();


}
int getValue(int* arr, int startBit, int endBit) {
  int sum = 0;
  for (int k = startBit; k <= endBit; k++) {
    if (arr[k] != -1) {
      sum += arr[k];
    } else {
      sum = -1;
      break;
    }
  }
  return sum;

}