# encoding: utf-8 """ From https://github.com/gaionim inspired by https://github.com/CodingGhost/DCF77-Transmitter reference https://en.wikipedia.org/wiki/DCF77 """ import datetime import struct from subprocess import call from ctypes import * class Sample(Structure): _fields_ = [("amplitude", c_double), ("timing", c_uint)] #with open("/tmp/upstream.bin", "rb") as file: # result = [] # x = Pippo() # while file.readinto(x) == sizeof(x): # result.append((x.a, x.t)) BASE = [1, 2, 4, 8, 10, 20, 40, 80] NUMS = 5 UP = 32767.0 #DOWN = 3276.0 DOWN = 0.0 filename = "/tmp/pippo.rfa" # from https://git.s7t.de/dcf77/dcf77-python/blob/master/dcf77/dcfvalue.py class DCF77Value: def __init__(self): self.hour = 00 self.minute = 00 self.second = 00 self.day = 00 self.month = 00 self.year = 0000 self.data = [] self.parity = True self.data = [] self.chunklist = { "startbit" : [0, 1], "weather" : [1, 14], "callbit" : [15, 1], "cest_announce" : [16, 1], "cest" : [17, 1], "cet" : [18, 1], "leap_second_announce" : [19, 1], "start_time" : [20, 1], "minute" : [21, 7], "minute_parity" : [28, 1], "hour" : [29, 6], "hour_parity" : [35, 1], "day_month" : [36, 6], "day_week" : [42, 3], "month" : [45, 5], "year" : [50, 8], "date_parity" : [58, 1], "date" : [36, 22], "minute_mark" : [59, 1], } def getByte(self, byte): if len(self.data) >= byte: return self.data[byte] return False def getChunk(self, chunk): start = self.chunklist[chunk][0]; end = start + self.chunklist[chunk][1]; if len(self.data) >= end: return self.data[start:end] return False def getCurrentBitCount(self): return len(self.data) def setMinute(self): data = self.getChunk("minute") if data == False or len(data) < 7: return self.minute = (data[0] + (2 * data[1]) + (4 * data[2]) + (8 * data[3]) + (10 * data[4]) + (20 * data[5]) + (40 * data[6])) def setHour(self): data = self.getChunk("hour"); print data if data == False or len(data) < 6: return self.hour = (data[0] + (2 * data[1]) + (4 * data[2]) + (8 * data[3]) + (10 * data[4]) + (20 * data[5])) def setDay(self): data = self.getChunk("day_month") if data == False or len(data) < 6: return self.day = (data[0] + (2 * data[1]) + (4 * data[2]) + (8 * data[3]) + (10 * data[4]) + (20 * data[5])) def setMonth(self): data = self.getChunk("month") if data == False or len(data) < 5: return self.month = (data[0] + (2 * data[1]) + (4 * data[2]) + (8 * data[3]) + (10 * data[4])) def setYear(self): data = self.getChunk("year") if data == False or len(data) < 8: return; self.year = (data[0] + (2 * data[1]) + (4 * data[2]) + (8 * data[3]) + (10 * data[4]) + (20 * data[5]) + (40 * data[6]) + (80 * data[7]) + 2000) def getMinute(self): return self.minute def getHour(self): return self.hour def getDay(self): return self.day def getMonth(self): return self.month def getYear(self): return self.year def getTime(self): return "%02d:%02d" % (self.getHour(), self.getMinute()) def getDate(self): return "%02d.%02d.%04d" % (self.getDay(), self.getMonth(), self.getYear()) def parse(self): self.setMinute() self.setHour() self.setDay() self.setMonth() self.setYear() # fine def int_to_bcd(value, num_bits): """ """ bits = [] for base in reversed(BASE[:num_bits]): if value >= base: bits.append("1") value -= base else: bits.append("0") return "".join(reversed(bits)) def add_crc(value, odd=True): num = value.count("1") p = num % 2 if(( p == 1 ) and odd) or ( p==0 and not odd) : return "%s1" % value else: return "%s0" % value def to_dcf77(data): time_code = ["011111111100000",] time_code.append("11") if data.dst(): time_code.append("10") else: time_code.append("01") time_code.append("0") #leap second time_code.append("1") time_code.append(add_crc(int_to_bcd(data.minute, 7))) time_code.append(add_crc(int_to_bcd(data.hour, 6))) date = [int_to_bcd(data.day, 6),] date.append(int_to_bcd(data.weekday()+1, 3)) date.append(int_to_bcd(data.month, 5)) date.append(int_to_bcd(data.year - 2000, 8)) time_code.append(add_crc("".join(date))) return "".join(time_code) def modulate(value=None): if value is None: # last secons return [(UP,1000000000)] else: if value == 0: return [(DOWN,100000000), (UP,900000000)] else: return [(DOWN,200000000), (UP,800000000)] if __name__ == "__main__": with open(filename, "wb") as f: now = datetime.datetime.now() # tolgo secondi per arrivare a inizio minuto # aggiungo 1 per arrivare a prossimo minuto # aggiungo 1 perchè ad ogni minuto, comunico il minuto dopo start = now + datetime.timedelta(minutes=2) - \ datetime.timedelta(microseconds = now.microsecond, seconds = now.second ) if now.second >= 58: # not enougth time start = start + datetime.timedelta(minutes=1) sample = Sample() for i in range(NUMS): for val in ( int(v) for v in to_dcf77(start + datetime.timedelta(i))): print val, ":", for amplitude, timing in modulate(val): sample.amplitude = amplitude sample.timing = timing #f.write(struct.pack("!fI", amplitude, timing)) f.write(sample) print "%s, %s" % (amplitude, timing) # inizio minuto print "chiusura :", for amplitude, timing in modulate(): sample.amplitude = amplitude sample.timing = timing #f.write(struct.pack("!fI", amplitude, timing)) f.write(sample) print "%s, %s" % (amplitude, timing) trigger = start - datetime.timedelta(minutes=1) call(["sudo", "./rpitx", "-m", "RFA", "-i", filename, "-f", "77.500", "-l","-c","1"])