From 1428b7923b101e5ecc4699d509a6b77a36e068fd Mon Sep 17 00:00:00 2001 From: zlax Date: Mon, 1 Jul 2024 11:21:37 +0300 Subject: [PATCH] init --- README.md | 7 ++- rtctimestampbias.csv | 0 rtctimestampbias.ino | 51 +++++++++++++++++++ rtctimestampbias.py | 119 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 rtctimestampbias.csv create mode 100644 rtctimestampbias.ino create mode 100755 rtctimestampbias.py diff --git a/README.md b/README.md index c6817c0..fcbaa99 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ -# rtctimestampbias +# RTC timestamp bias -Saving and comparing timestamps of the microcontroller's real time clock \ No newline at end of file +Saving and comparing timestamps of the microcontroller's real time clock + +- `rtctimestampbias.py` - main script for saving and comparing timestamps (`serial` and `csv` packages are required) +- `rtctimestampbias.ino` - sample sketch for Arduino with DS1307RTC diff --git a/rtctimestampbias.csv b/rtctimestampbias.csv new file mode 100644 index 0000000..e69de29 diff --git a/rtctimestampbias.ino b/rtctimestampbias.ino new file mode 100644 index 0000000..63f8fe4 --- /dev/null +++ b/rtctimestampbias.ino @@ -0,0 +1,51 @@ +// RTC timestamp bias: Arduino with DS1307RTC example +// https://gitlab.com/simplemicrocontrollers/rtctimestampbias +#include +#include + +// Time bias correction variables: +int correctionBias = 0; // Daily clock correction in seconds +byte correctionHour = 3; // 3AM - daily correction time +long correctionCheck = 300000; +bool correctionReady = true; +Thread correctionThread = Thread(); // Time bias correction thread + +void setup() { + Serial.begin(9600); // Initializes the Serial connection @ 9600 baud for debug + while (!Serial); // Wait until Arduino Serial Monitor opens + setSyncProvider(RTC.get); // The function to get the time from the RTC + if(timeStatus()!= timeSet) { // Checking the time setting + Serial.println("Unable to sync with the RTC"); + } else { +// Serial.println("RTC has set the system time"); + Serial.println(now()); // Sending a timestamp to the serial port if a RTC is detected + } + + // Time bias correction thread initialization: + correctionThread.onRun(correctionLoop); + correctionThread.setInterval(correctionCheck); +} + +void loop() { + // Threads: + if (correctionThread.shouldRun()) + correctionThread.run(); +} + +void correctionLoop() { + if (hour() == correctionHour) { + if (correctionReady) { + tmElements_t RTCtime; + RTC.read(RTCtime); + time_t RTCtimestamp; + RTCtimestamp = makeTime(RTCtime); + tmElements_t timeNew; + time_t newTimestamp = RTCtimestamp - correctionBias; // minus correctionBias seconds everyday + // if ((day() % 5) == 0) newTimestamp = newTimestamp - 1; // minus 1 sec every 5 days (-0.2sec everyday) + breakTime(newTimestamp, timeNew); + RTC.write(timeNew); + setSyncProvider(RTC.get); + correctionReady = false; + } + } else correctionReady = true; +} diff --git a/rtctimestampbias.py b/rtctimestampbias.py new file mode 100755 index 0000000..0a44ac1 --- /dev/null +++ b/rtctimestampbias.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# the following packages need to be installed via pip: +# serial, csv + +import serial.tools.list_ports +import csv +import time +from datetime import datetime +from optparse import OptionParser +from sys import argv +from os import path + +# RTC timestamp bias: saving and comparing timestamps +# of the microcontroller's real time clock +# https://gitlab.com/simplemicrocontrollers/rtctimestampbias + +version = "0.1" +filename = "rtctimestampbias.csv" + +def ShowPorts(option, opt, value, parser): + number = 0 + for port in ports: + if number > 0: print("---") + print(f"port {number}: {port.name}") + print(f"hwid: {port.hwid}") + print(f"desc: {port.description}") + number += 1 + +def SaveByNumber(number): + SaveValue(ports[int(number)].device) + +def SaveByName(name): + for port in ports: + if port.name == name: + SaveValue(port.device) + +def SaveValue(device): + ser = serial.Serial(device, 9600) + response = ser.readline() + current_host_time = datetime.now() + decoded_response = int(response.decode('utf-8')) + ser.close() + print("Serial device timestamp:") + print(decoded_response) + hosttimestamp = int(round(current_host_time.timestamp())) + print("Host device timestamp:") + print(hosttimestamp) + csvdatarow = [[current_host_time, hosttimestamp, decoded_response]] + with open(filename, 'a') as csvfile: + csvwriter = csv.writer(csvfile) + for row in csvdatarow: + csvwriter.writerow(row) + +def CalculateCSVdata(option, opt, value, parser): + hostFirst = None + deviceFirst = None + hostLast = None + deviceLast = None + with open(filename, newline='') as csvfile: + spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|') + rownumber = 0 + for row in spamreader: + if rownumber == 0: + hostFirst = ', '.join(row).split(',')[2] + deviceFirst = ', '.join(row).split(',')[3] + hostLast = ', '.join(row).split(',')[2] + deviceLast = ', '.join(row).split(',')[3] + rownumber += 1 + print(f"First timestamp of the host: {hostFirst}") + print(f"First timestamp of the device: {deviceFirst}") + print(f"Last timestamp of the host: {hostLast}") + print(f"Last timestamp of the device: {deviceLast}") + hostDiff = int(hostLast) - int(hostFirst) + deviceDiff = int(deviceLast) - int(deviceFirst) + totalDiff = deviceDiff - hostDiff + print(f"Host diff: {hostDiff}; device diff: {deviceDiff}; host/device total diff: {totalDiff}") + resultBias = (86400 / deviceDiff) * totalDiff + print(f"Resulting daily clock bias in seconds: {resultBias}") + +def CMDOptions(): + class FormatedParser(OptionParser): + def format_epilog(self, formatter): + return self.epilog + usage = "usage: %prog [options]" + progname = path.basename(__file__) + epilog = ("".join(["Examples:\n ", + progname, " -l\n ", + progname, " -n 2\n ", + progname, " -d ttyUSB0\n ", + progname, " -c\n"])) + opts = FormatedParser(usage=usage, version="%prog " + version, + epilog=epilog) + opts.add_option('-l', '--list', action="callback", + callback=ShowPorts, help="show information about each port") + opts.add_option('-n', '--num', action="store", type="string", + dest="num", metavar="number", default=False, + help="save data by port number") + opts.add_option('-d', '--dev', action="store", type="string", + dest="dev", metavar="name", default=False, + help="save data by device name") + opts.add_option('-c', '--calc', action="callback", + callback=CalculateCSVdata, help="calculate data from csv file") + options, value = opts.parse_args() + if options.num: + SaveByNumber(options.num) + if options.dev: + SaveByName(options.dev) + if len(argv[1:]) == 0: + print ("no argument given\n") + opts.print_help() + +if __name__ == "__main__": + ports = list(serial.tools.list_ports.comports()) + try: + CMDOptions() + except KeyboardInterrupt: + exit()