#!/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):

	global DEBUG
	global yearold
	global monthold
	global dayold
	global hourold

	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

	if DEBUG:
		print "Die erkannte Zeit: " + str(hour) + ":" + str(minute) + ":XX am " + str(day) + "." + str(month) + "." + str(year)
	# Pruefen des Datums aus vorangegangenem Lauf
	if year != yearold or month != monthold or day != dayold or hour != hourold:
		if DEBUG:
			print "ist ungleich der alten Referenzzeit: " + str(hourold) + ":XX:XX am " + str(dayold) + "." + str(monthold) + "." + str(yearold)
		yearold = year
		monthold = month
		dayold = day
		hourold = hour
		if DEBUG:
                	print "Die Referenzzeit wird auf die erkannte Zeit eingestellt und die DCF77 Auswertung wird wiederholt"
		return None
	if DEBUG:
		print "Ist gleich der alten Referenzzeit: " + str(hourold) + ":XX:XX am " + str(dayold) + "." + str(monthold) + "." + str(yearold)

	# 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 38 auf input und 40 auf output setzen
GPIO.setup(38, GPIO.IN)
GPIO.setup(40, GPIO.OUT)

# Zustand des GPIO-Pins einlesen
old_state = int(GPIO.input(38))

begin_found = False
begin_bit_found = False
Scanning = True
bit_seq = [int] * 59
first_round = True
counter = 0
yearold = 9999
monthold = 99
dayold = 99
hourold = 99
 
# Schleife, bis das Signal decodiert wurde
if DEBUG:
	print "Referenzdatum gesetzt auf: " + str(hourold) + ":XX:XX am " + str(dayold) + "." + str(monthold) + "." + str(yearold)
	print str("Warte auf Minutenbeginn ...")
while Scanning:
	# Get microseconds dt.microsecond
	# GPIO lesen
	if first_round:
		start_time = datetime.now()
                first_round = False

	GPIO.wait_for_edge(38, GPIO.BOTH)
	# Pegelwechsel am Eingang
	dt = datetime.now() - start_time
	start_time = datetime.now()

	if dt.seconds == 1:
			begin_bit_found = True
	elif old_state == GPIO.HIGH and begin_bit_found and dt.microseconds < 140000:
			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) < 140000 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.845)
					# 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")

					if DEBUG:
						print "Systemzeit gesetzt auf " + str(dcf77_time)
						os.system("echo " + time_date_str + " >> /home/pi/dcf77decode.txt")

					Scanning = False

	old_state = int(GPIO.input(38))
	# Angeschlossene LED an PIN 40 blinken lassen um Sync. zu signalisieren
	if old_state == GPIO.HIGH:
		GPIO.output(40, GPIO.HIGH)
	elif old_state == GPIO.LOW:
		GPIO.output(40, GPIO.LOW)

# Bye


