F5OEO-rpitx/Not_working_with_v2/setTime.py

191 wiersze
5.6 KiB
Python
Executable File

#!/usr/bin/env python
# encoding: utf-8
"""
inspired by https://github.com/CodingGhost/DCF77-Transmitter
reference
https://en.wikipedia.org/wiki/DCF77
"""
import argparse
from ctypes import *
import datetime
import logging
import os
import struct
from subprocess import call
import tempfile
logging.basicConfig()
logger = logging.getLogger(__name__)
class Sample(Structure):
'''
Helper for writing binary data to RFA file
'''
_fields_ = [("amplitude", c_double), ("timing", c_uint)]
def __init__(self, amplitude, timing):
self.amplitude = amplitude
self.timing = timing
class Dcf77(object):
'''
Utility for working dcf77 standard
https://en.wikipedia.org/wiki/DCF77
'''
BASE = [1, 2, 4, 8, 10, 20, 40, 80]
@staticmethod
def int_to_bcd(value, num_bits):
"""
"""
bits = []
for base in reversed(Dcf77.BASE[:num_bits]):
if value >= base:
bits.append("1")
value -= base
else:
bits.append("0")
return "".join(reversed(bits))
@staticmethod
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
@classmethod
def to_dcf77(cls, data):
'''
Convert datetime to list of bit in dcf77 encoding
see https://en.wikipedia.org/wiki/DCF77
:param data: datetime.datetime
'''
time_code = ["0", # start of minute
"11111111100000", # wheather, warnngs or other data
"1", # Abnormal transmitter / backup antenna
"0", # Summer time announcement
]
time_code.append("00") # cest and cet bit
time_code.append("0") # leap second
time_code.append("1") # start encoding time
time_code.append(cls.add_crc(cls.int_to_bcd(data.minute, 7)))
time_code.append(cls.add_crc(cls.int_to_bcd(data.hour, 6)))
date = [cls.int_to_bcd(data.day, 6), ]
date.append(cls.int_to_bcd(data.weekday() + 1, 3))
date.append(cls.int_to_bcd(data.month, 5))
date.append(cls.int_to_bcd(data.year - 2000, 8))
time_code.append(cls.add_crc("".join(date)))
return "".join(time_code)
@staticmethod
def modulate(encoded, UP=32767, DOWN=0):
'''
dcf77 modulation
1 bit per second
0.1 sec down = 0
0.2 sec down = 1
1 sec up = end of second
return generator of tuple returning (value, time in milliseconds)
:param encoded: sequence of 01 representing message
:param UP: value for 100% modulation
:param DOWN: value for 15% modulation
I do not know why, but 0 seems to work
'''
for value in encoded:
if value in ("0", 0):
yield (DOWN, 100000000)
yield (UP, 900000000)
elif value in ("1", 1):
yield (DOWN, 200000000)
yield (UP, 800000000)
else:
raise ValueError("Only 0|1")
# last second no modulation
yield (UP, 1000000000)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Call rpitx to set dcf77 clock",
epilog="default wire on GPIO 18 ( pin 12) and 5 minutes of transmission")
parser.add_argument("-v", "--verbose", help="increase output verbosity",
action="store_true")
parser.add_argument("-4", "--gpio4", help="wire on GPIO 4 ( pin 7)",
action="store_true")
parser.add_argument("-n", "--nums", help="number of minutes of transmission",
type=int,
default=5)
args = parser.parse_args()
if args.verbose:
logger.setLevel(logging.DEBUG)
NUMS = args.nums # transmit for NUMS minutes
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(microseconds=now.microsecond, # start of current minute
seconds=now.second) + \
datetime.timedelta(minutes=1) # start of next minute
if now.second >= 58:
# not enougth time, add one more minute
start = start + datetime.timedelta(minutes=1)
filename = None
with tempfile.NamedTemporaryFile("wb", delete=False) as f:
filename = f.name
for i in range(1, NUMS + 1):
# i start with 1 because now whi transmit next minute ( now+1
# minute)
data = start + datetime.timedelta(minutes=i)
encoded = Dcf77.to_dcf77(data)
logger.debug("%s -> %s", data, encoded)
for amplitude, timing in Dcf77.modulate(encoded):
sample = Sample(amplitude, timing)
f.write(sample)
logger.debug("%s, %s", amplitude, timing)
print "waiting %s for syncronization..." % start
while True:
# whaiting for start of minute
if datetime.datetime.now() >= start:
break
cmd = ["sudo", "./rpitx", "-m", "RFA", "-i",
filename, "-f", "77.500"]
if args.gpio4:
cmd.extend(["-c", "1"])
logger.debug(cmd)
ret = call(cmd)
logger.debug("ret = %s", ret)
if ret == 0:
print "End of transmission, hope your clock is set."
else:
print "Something got wrong, check for errors"
if filename is not None:
os.remove(filename)