From 27b47163b4cfb3ecd787e650b5eec6fc51e96340 Mon Sep 17 00:00:00 2001 From: Roman Kovalev Date: Mon, 31 Aug 2020 23:06:12 +0300 Subject: [PATCH] #7 --- SportiduinoPQ.py | 37 +++++++++++++++++++++----- sportiduino.py | 67 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 81 insertions(+), 23 deletions(-) diff --git a/SportiduinoPQ.py b/SportiduinoPQ.py index 43efc8b..9dfd0dc 100755 --- a/SportiduinoPQ.py +++ b/SportiduinoPQ.py @@ -5,15 +5,16 @@ import platform import re import datetime +import time import serial import json import csv import design from serial import Serial -from sportiduino import Sportiduino, SportiduinoException, SportiduinoTimeout +from sportiduino import Sportiduino, SportiduinoException, SportiduinoTimeout, SportiduinoNoCardPresentException from basestation import BaseStation -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from PyQt5 import uic, QtWidgets, QtPrintSupport, QtCore, sip from PyQt5.QtCore import QSizeF, QSettings from PyQt5.QtPrintSupport import QPrinter @@ -21,6 +22,7 @@ from PyQt5.QtCore import QTranslator from PyQt5.QtCore import QLocale from PyQt5.QtCore import QCoreApplication +from PyQt5.QtCore import QTimeZone from six import int2byte _translate = QCoreApplication.translate @@ -102,6 +104,21 @@ def __init__(self, config): self.ui.sbCurPwd2.setValue(bs_config.password[1]) self.ui.sbCurPwd3.setValue(bs_config.password[2]) + ianaIds = QTimeZone.availableTimeZoneIds() + all_timezones = sorted({QTimeZone(id).offsetFromUtc(datetime.now()) for id in ianaIds}) + tzlocaloffset = time.localtime().tm_gmtoff + tzlocalname = None + for dt in all_timezones: + tz = timezone(timedelta(seconds=dt)) + tzname = tz.tzname(None) + if dt == tzlocaloffset: + tzlocalname = tzname + self.ui.cbTimeZone.addItem(tzname, dt) + if tzlocalname is not None: + self.ui.cbTimeZone.setCurrentText(tzlocalname) + else: + self.ui.cbTimeZone.setCurrentText(timezone(offset=timedelta(0)).tzname(None)) + def closeEvent(self, event): self.config.setValue('geometry', self.saveGeometry()) @@ -133,15 +150,14 @@ def Connect_clicked(self): self._apply_pwd(curPass) #self.sportiduino.beep_ok() - self.connected = True self.log('\n' + self.tr("Master station {} on port {} is connected").format(self.sportiduino.version, self.sportiduino.port)) self.ui.Connect.setText(_translate("MainWindow", "Disconn.")) + self.connected = True self.read_ms_config() except Exception as err: self._process_error(err) - self.connected = False raise err def ReadCard_clicked(self): @@ -161,7 +177,10 @@ def ReadCard_clicked(self): self._show_card_data(data, card_type) self._save_card_data_to_file(data) - + + except SportiduinoNoCardPresentException as err: + self.log(self.tr("Card not found. Place card near reader and try again")) + except Exception as err: self._process_error(err) raise err @@ -504,6 +523,9 @@ def read_ms_config(self): ms_config = self.sportiduino.read_settings() if ms_config.antenna_gain is not None: self.ui.cbMsAntennaGain.setCurrentIndex(ms_config.antenna_gain - 2) + if ms_config.timezone is not None: + tz = timezone(ms_config.timezone) + self.ui.cbTimeZone.setCurrentText(tz.tzname(None)) def btnMsConfigRead_clicked(self): if not self._check_connection(): @@ -522,7 +544,8 @@ def write_ms_config(self): return try: - self.sportiduino.write_settings(self.ui.cbMsAntennaGain.currentIndex() + 2) + tz = timedelta(seconds=self.ui.cbTimeZone.currentData()) + self.sportiduino.write_settings(self.ui.cbMsAntennaGain.currentIndex() + 2, tz) except Exception as err: self._process_error(err) raise err @@ -735,7 +758,7 @@ def __init__(self): self._log_file = open(os.path.join('log','log{:%Y%m%d}.txt'.format(datetime.now())),'a') def __call__(self, text): - self._log_file.write(text) + self._log_file.write(text + '\n') def __del__(self): print("Close log file") diff --git a/sportiduino.py b/sportiduino.py index e39471f..4ebafc1 100644 --- a/sportiduino.py +++ b/sportiduino.py @@ -139,8 +139,26 @@ def __str__(self): return 'v%d.%d.%s' % (self.major, self.minor, vers_suffix) class Config(object): - def __init__(self, antenna_gain = 0): + def __init__(self, antenna_gain=0, timezone=timedelta()): self.antenna_gain = antenna_gain + self.timezone = timezone + + @classmethod + def unpack(cls, config_data): + timezone = timedelta() + if len(config_data) > 1: + timezone = timedelta(minutes=byte2int(config_data[1])*15) + if timezone < -timedelta(hours=24) or timezone > timedelta(hours=24): + timezone = timedelta() + return cls(antenna_gain = byte2int(config_data[0]), + timezone = timezone) + + def pack(self): + config_data = b'' + config_data += int2byte(self.antenna_gain) + print(self.timezone.total_seconds()) + config_data += int2byte(int(self.timezone.total_seconds()/60/15)) + return config_data class SerialProtocol(object): @@ -268,6 +286,8 @@ def __init__(self, port=None, debug=False, logger=None, translator=None): self._serialproto = Sportiduino.SerialProtocol(Sportiduino.START_BYTE, self._log_debug) + self.version = None + errors = '' if port is not None: self._connect_master_station(port) @@ -276,6 +296,7 @@ def __init__(self, port=None, debug=False, logger=None, translator=None): if platform.system() == 'Linux': scan_ports = [os.path.join('/dev', f) for f in os.listdir('/dev') if re.match('ttyUSB.*', f)] + scan_ports.sort(reverse=True) elif platform.system() == 'Windows': scan_ports = ['COM' + str(i) for i in range(32)] else: @@ -315,11 +336,11 @@ def reconnect(self): self._connect_master_station(self._serial.port) - def read_version(self): + def read_version(self, timeout=None): """Read master station firmware version. @return: Version object. """ - code, data = self._send_command(Sportiduino.CMD_READ_VERS) + code, data = self._send_command(Sportiduino.CMD_READ_VERS, timeout=timeout) if code == Sportiduino.RESP_VERS: data_len = len(data) if data_len == 3: @@ -402,7 +423,7 @@ def init_card(self, card_number, page6=None, page7=None): params += Sportiduino._to_str(t, 4) params += page6[:5] params += page7[:5] - return self._send_command(Sportiduino.CMD_INIT_CARD, params, wait_response=True) + return self._send_command(Sportiduino.CMD_INIT_CARD, params, wait_response=True, timeout=3) def init_backupreader(self): @@ -484,14 +505,13 @@ def apply_pwd(self, pwd=(0, 0, 0), flags=0): def read_settings(self): code, data = self._send_command(Sportiduino.CMD_READ_SETTINGS) if code == Sportiduino.RESP_SETTINGS: - return Sportiduino.Config(antenna_gain=byte2int(data[0])) + return Sportiduino.Config.unpack(data) else: raise SportiduinoException("Read settings failed") - def write_settings(self, antenna_gain): - params = b'' - params += int2byte(antenna_gain) + def write_settings(self, antenna_gain, timezone): + params = Sportiduino.Config(antenna_gain, timezone).pack() self._send_command(Sportiduino.CMD_WRITE_SETTINGS, params) @@ -552,10 +572,7 @@ def _set_mode(self, mode): def _connect_master_station(self, port): try: - self._serial = Serial(port, baudrate=9600, timeout=5) - # Master station reset on serial open. - # Wait little time for it startup - time.sleep(2) + self._serial = Serial(port, baudrate=38400, timeout=3) except (SerialException, OSError): raise SportiduinoException(Sportiduino._translate("sportiduino","Could not open port {}").format(port)) @@ -564,15 +581,29 @@ def _connect_master_station(self, port): except (SerialException, OSError): raise SportiduinoException(Sportiduino._translate("sportiduino","Could not flush port {}").format(port)) + # Master station with DTR connected resets on serial open. + # It responds on the second attempt. + for baudrate in (38400, 38400, 9600): + try: + self._serial.baudrate = baudrate + self._log_debug("Try find master station on port '%s', baudrate %d" % (port, self._serial.baudrate)) + self.version = self.read_version(timeout=2) + except SportiduinoTimeout: + self._log_debug("No response") + else: + break + + if self.version is None: + raise SportiduinoTimeout("No response") + self.port = port self.baudrate = self._serial.baudrate - self.version = self.read_version() - if self.version is not None: - self._log_info("Master station %s on port '%s' is connected" % (self.version, port)) + self._log_info("Master station %s on port '%s' at %d is connected" % (self.version, port, self.baudrate)) def _send_command(self, code, parameters=None, wait_response=True, timeout=None): resp_code, data = self._serialproto.send_command(self._serial, code, parameters, wait_response, timeout) + return Sportiduino._preprocess_response(resp_code, data, self._log_debug) @@ -629,7 +660,7 @@ def _preprocess_response(func, data, log_debug): raise SportiduinoException(Sportiduino._translate("sportiduino","Can't read EEPROM")) elif err_code == Sportiduino.ERR_CARD_NOT_FOUND: if card_type == 0 or card_type == 0xff: - raise SportiduinoException(Sportiduino._translate("sportiduino","Card is not found")) + raise SportiduinoNoCardPresentException(Sportiduino._translate("sportiduino","Card is not found")) else : raise SportiduinoException(Sportiduino._translate("sportiduino","Unsupported card type = {}").format(card_type)) elif err_code == Sportiduino.ERR_UNKNOWN_CMD: @@ -751,6 +782,10 @@ class SportiduinoException(Exception): pass +class SportiduinoNoCardPresentException(Exception): + pass + + class SportiduinoTimeout(SportiduinoException): pass