#!/usr/bin/python
import time
import os
import RPi.GPIO as GPIO
from datetime import datetime
from datetime import timedelta
from array import *

# Fuer Debug-Ausgabe
DEBUG = True

# Unterprogramm zum Umwandeln BCD nach Dezimal
def bcd2dez(b3, b2, b1, b0):
	result = b0 + b1 * 2 + b2 * 4 + b3 * 8
	return result


# Paritaetspruefung (gerade P.)
# Es werden der Start- und Ende-Index im Array angegeben
def parity(start, end, bit_arr):
	i = start
	ipar = 0
	while i <= end:
		ipar = ipar + bit_arr[i]
		i = i + 1
	return (ipar % 2)


# Unterprogramm zum Decodieren des DCF77-Signals
def decodeDCF77(bit_seq):
	if bit_seq[0] != 0 or bit_seq[20] != 1:
		return None
	# Minute (BCD) berechnen
	minute = bcd2dez(bit_seq[24], bit_seq[23], bit_seq[22], bit_seq[21])
	minute = minute + 10 * bcd2dez(0, bit_seq[27], bit_seq[26], bit_seq[25])
	if parity(21, 27, bit_seq) != bit_seq[28]:
		return None

	# Stunde (BCD) berechnen
	hour = bcd2dez(bit_seq[32], bit_seq[31], bit_seq[30], bit_seq[29])
        hour = hour + 10 * bcd2dez(0, 0, bit_seq[34], bit_seq[33])
	if parity(29, 34, bit_seq) != bit_seq[35]:
		return None

	# Jahr (BCD) berechnen
	year = bcd2dez(bit_seq[53], bit_seq[52], bit_seq[51], bit_seq[50])
	year = year + 10 * bcd2dez(bit_seq[57], bit_seq[56], bit_seq[55], bit_seq[54]) + 2000
	# Monat (BCD) berechen
	month = bcd2dez(bit_seq[48], bit_seq[47], bit_seq[46], bit_seq[45]) + bit_seq[49] * 10
	# Tag (BCD) berechnen
	day = bcd2dez(bit_seq[39], bit_seq[38], bit_seq[37], bit_seq[36])
	day = day + 10 * bcd2dez(0, 0, bit_seq[41], bit_seq[40])
	if parity(36, 57, bit_seq) != bit_seq[58]:
		return None

	# Umrechnen ins datetime-Format
	second = 0
	microsecond = 0
	dcf77_time = datetime(year, month, day, hour, minute, second, microsecond)
	return dcf77_time


# Hautprogramm zum Abfragen des DCF77-Signals

# RPi.GPIO Layout verwenden (wie Pin-Nummern)
GPIO.setmode(GPIO.BOARD)

# Pin 11 (GPIO 17) auf Input setzen
GPIO.setup(11, GPIO.IN)

# Zustand des GPIO-Pins einlesen
old_state = int(GPIO.input(11))

begin_found = False
begin_bit_found = False
Scanning = True
bit_seq = [int] * 59
first_round = True
counter = 0

# Schleife, bis das Signal decodiert wurde
if DEBUG:
	print str("Warte auf Minutenbeginn ...")
while Scanning:
	# GPIO lesen
	if first_round:
		start_time = datetime.now()
		first_round = False

	if int(GPIO.input(11)) != old_state:
		# Pegelwechsel am Eingang
		dt = datetime.now() - start_time
		start_time = datetime.now()

		if dt.seconds == 1:
			begin_bit_found = True
    # fuer neuere Raspberries (z. B. Pi 2 mit 4 Kernen):
    # wenn die Dekodierung nicht klappt statt 110000 besser 
    # 140000 verwenden
		elif old_state == GPIO.HIGH and begin_bit_found and dt.microseconds < 110000:
			begin_bit_found = False
			begin_found = True
			counter = 0
			bit_seq[counter] = 0
			if DEBUG:
				print str(time.time()) + "   " + str(counter) + " " + str(0)
		elif begin_found and old_state == GPIO.HIGH:
			counter = counter + 1
			bit_seq[counter] = 0 if int(dt.microseconds) < 110000 else 1
			if DEBUG:
				print str(time.time()) + "   " + str(counter) + " " + str(bit_seq[counter])
			# vorletzte Sekunde
			if counter == 58:
				begin_found = False
				dcf77_time = decodeDCF77(bit_seq)
				if dcf77_time is not None:
					# letzte Sekunde abwarten
					time.sleep(1)
					# Date/Time-String formatieren
					time_date_str = "\"{:4d}-{:02d}-{:02d} {:02d}:{:02d}:00\"".format(
					dcf77_time.year, dcf77_time.month, dcf77_time.day, dcf77_time.hour, dcf77_time.minute)
					# Systemzeit setzen
					os.system("date -s " + time_date_str + " > /dev/null")
					print str(dcf77_time)
					Scanning = False

		old_state = int(GPIO.input(11))

# Bye
