diff --git a/.project b/.project new file mode 100644 index 0000000..ac0151c --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + SportiduinoPQ + + + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 0000000..d001f0a --- /dev/null +++ b/.pydevproject @@ -0,0 +1,5 @@ + + +Default +python interpreter + diff --git a/CHANGELOG.md b/CHANGELOG.md index 85b504d..9860eb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## [0.7.0] - 2019-07-23 +- Added russian localization +- Redesigned UI +- Added UI to work with a base station using UART +- Fixed bugs ## [0.6.1] - 2018-10-23 ### del some functions for version 1.4.2 sportiduino diff --git a/README.md b/README.md index b4322d8..68ece89 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # sportiduinoPQ -### version 0.6.1 +### version 0.7.0 In the [last release](https://github.com/alexandervolikov/SportiduinoPQ/releases), you can download the program with the exe file for Windows systems, the installation is not required. @@ -24,4 +24,4 @@ https://github.com/alexandervolikov/sportIDuino) Manual available in user manual at https://github.com/alexandervolikov/sportiduino -![](https://raw.githubusercontent.com/alexandervolikov/SportiduinoPQ/master/image/main1.JPG) \ No newline at end of file +![](/images/main1.JPG) \ No newline at end of file diff --git a/README.ru.md b/README.ru.md index dfbcbac..805b247 100644 --- a/README.ru.md +++ b/README.ru.md @@ -1,6 +1,6 @@ # sportiduinoPQ -### версия 0.6.1 +### версия 0.7.0 В [последнем релизе](https://github.com/alexandervolikov/SportiduinoPQ/releases) можно скачать программу с exe файлом для Windows систем, установка не требуется @@ -23,4 +23,4 @@ pyinstaller --onefile --noconsole SportiduinoPQ.py Инструкция находится в руководстве пользователя https://github.com/alexandervolikov/sportiduino -![](https://raw.githubusercontent.com/alexandervolikov/SportiduinoPQ/master/image/main1.JPG) \ No newline at end of file +![](/images/main1.JPG) \ No newline at end of file diff --git a/SportiduinoPQ.py b/SportiduinoPQ.py index 4be926a..daebc88 100644 --- a/SportiduinoPQ.py +++ b/SportiduinoPQ.py @@ -7,30 +7,44 @@ import json import copy import design -from sportiduino import Sportiduino +import traceback + +from serial import Serial +from sportiduino import Sportiduino, BaseStation from datetime import datetime, timedelta from PyQt5 import uic, QtWidgets, QtPrintSupport, QtCore, sip -from PyQt5.QtCore import QSizeF, QDateTime +from PyQt5.QtCore import QSizeF, QDateTime, QTime from PyQt5.QtPrintSupport import QPrinter from PyQt5.QtWidgets import QApplication, QFileDialog +from PyQt5.QtCore import QTranslator +from PyQt5.QtCore import QLocale +from PyQt5.QtCore import QCoreApplication +from six import int2byte, byte2int, iterbytes, print_, PY3 + +_translate = QCoreApplication.translate class App(QtWidgets.QMainWindow, design.Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) + self.setWindowTitle("SportiduinoPQ v0.7.0") + self.log ='' self.readData = [] self.dumpData = [] self.connected = False self.CardNum = '0' - self.StatNum = '0' - self.OldPass.setText('0') - self.NewPass.setText('0') - self.printerName.setText(QPrinter().printerName()) + self.printer = QPrinter() + self.printerName.setText(self.printer.printerName()) self.initTime = datetime.now() self.addText('{:%Y-%m-%d %H:%M:%S}'.format(self.initTime)) + + dt = QDateTime.currentDateTime() + tm = QTime(dt.time().hour(), dt.time().minute(), 0) + dt.setTime(tm) + self.dtCompetion.setDateTime(dt) self.Connec.clicked.connect(self.Connec_clicked) self.ReadCard.clicked.connect(self.ReadCard_clicked) @@ -49,11 +63,17 @@ def __init__(self): self.LoadSet.clicked.connect(self.LoadSet_clicked) self.SelectPrinter.clicked.connect(self.SelectPrinter_clicked) self.Print.clicked.connect(self.Print_clicked) + self.btnApplyPwd.clicked.connect(self.ApplyPwd_clicked) + self.btnCreateInfoCard.clicked.connect(self.CreateInfo_clicked) + self.btnReadInfo.clicked.connect(self.ReadInfo_clicked) + self.btnUartRead.clicked.connect(self.SerialRead_clicked) + self.btnUartWrite.clicked.connect(self.SerialWrite_clicked) + self.btnClearText.clicked.connect(self.ClearText_clicked) - - def Connec_clicked(self): + self.addText("") + if (self.connected == False): COM = 'COM' + self.choiseCom.currentText() try: @@ -62,338 +82,505 @@ def Connec_clicked(self): else: self.sportiduino = Sportiduino(COM,debug=True) + self.sbCurPwd1.setValue((self.sportiduino.password & 0xFF0000) >> 16) + self.sbCurPwd2.setValue((self.sportiduino.password & 0x00FF00) >> 8) + self.sbCurPwd3.setValue(self.sportiduino.password & 0x0000FF) + + self.showSettings(self.sportiduino.settings) + idx = (self.sportiduino.antennaGain >> 4) - 2 + self.cbAntennaGain.setCurrentIndex(idx) + self.sportiduino.beep_ok() self.connected = True - self.addText('\nmaster station is connected') + text = _translate("sportiduinopq","Master station {} on port {} is connected").format(self.sportiduino.version, self.sportiduino.port) + self.addText(text) - except: - self.addText('\nError') + except BaseException as err: + self._process_error(err) self.connected = False - - else: self.sportiduino.disconnect() - self.addText('\nmaster station is disconnected') + text = _translate("sportiduinopq","Master station is disconnected") + self.addText(text) self.connected = False - def ReadCard_clicked(self): - - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False: return try: - data = self.sportiduino.read_card(timeout = 0.5) - self.sportiduino.beep_ok() + self.addText(_translate("sportiduinopq","Read a card")) - self.readDataFormat(data) - self.saveDataJson(data) + raw_data = self.sportiduino.read_card_raw() + card_type = self.sportiduino.read_card_type() - except: - self.sportiduino.beep_error() - self.addText('\nError') - - + data = Sportiduino.raw_data_to_card_data(raw_data) - def InitCard_clicked(self): + self.showCardData(data, card_type) + self.saveCardDataJson(data) + + except BaseException as err: + self._process_error(err) - if (self.connected == False): - self.addText('\nmaster station is not connected') + def InitCard_clicked(self): + if self._check_connection() == False: return - text = self.cardLine.text() - if(text.isdigit()): - self.CardNum = text - else: - self.CardNum = '0' + try: + + self.addText(_translate("sportiduinopq","Initialize the participant card")) + + text = self.cardLine.text() + + if(text.isdigit()): + self.CardNum = text + else: + self.CardNum = '0' - num = int(self.CardNum) - if (num > 0 and num < 65000): + num = int(self.CardNum) + + if (num < Sportiduino.MIN_CARD_NUM or num > Sportiduino.MAX_CARD_NUM): + raise BaseException(_translate("sportiduinopq","Not correct card number")) - try: - self.sportiduino.init_card(num) - self.addText ('\ninit card number {}'.format(num)) - if (self.AutoIncriment.checkState() != 0): - self.AutoIn = True - self.CardNum = str(num + 1) - self.cardLine.setText(self.CardNum) - except: - self.addText('\nError') - - else: - self.addText("\nnot correct value") + code, data = self.sportiduino.init_card(num) + + if (self.AutoIncriment.checkState() != 0): + self.AutoIn = True + self.CardNum = str(num + 1) + self.cardLine.setText(self.CardNum) + + if code == Sportiduino.RESP_OK : + self.addText(_translate("sportiduinopq","The participant card N{} ({}) has been initialized successfully").format(num, Sportiduino.card_name(data[0]))) + + except BaseException as err: + self._process_error(err) def SetNum_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False: return - text = self.StationLine.text() - if(text.isdigit()): - self.StatNum = text - else: - self.StatNum = '0' + try: - num = int(self.StatNum) - if (num > 0 and num < 240): + self.addText(_translate("sportiduinopq","Write the master card to set number of a base station")) + num = self.sbStationNum.value() + + if num == 0 or num > 255: + raise BaseException(_translate("sportiduinopq","Not correct station number")) - try: - self.sportiduino.init_cp_number_card(num) - self.addText ('\nset CP number {}'.format(num)) - except: - self.addText('\nError') - - else: - self.addText("\nnot correct value") + self.sportiduino.init_cp_number_card(num) + self._master_card_ok() + + except BaseException as err: + self._process_error(err) def SetTime_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False : return try: + + self.addText(_translate("sportiduinopq","Write the master card to set clock of a base station. Put the card on a base station after second signal")) self.sportiduino.init_time_card(datetime.utcnow() + timedelta(seconds=3)) - self.addText ('\nset time') - except: - self.addText('\nError') - sportiduino.beep_error() + self._master_card_ok() + + except BaseException as err: + self._process_error(err) def SetStart_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False : return try: - self.sportiduino.init_cp_number_card(240) - self.addText ('\nset start statnion') - except: - self.addText('\nError') + + self.addText(_translate("sportiduinopq","Write the master card to set a base station as the start station")) + self.sportiduino.init_cp_number_card(Sportiduino.START_STATION) + self.sbStationNum.setValue(Sportiduino.START_STATION) + self._master_card_ok() + + except BaseException as err: + self._process_error(err) def SetFinish_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False: return try: - self.sportiduino.init_cp_number_card(245) - self.addText ('\nset finish statnion') - except: - self.addText('\nError') - + + self.addText(_translate("sportiduinopq","Write the master card to set a base station as the finish station")) + self.sportiduino.init_cp_number_card(Sportiduino.FINISH_STATION) + self.sbStationNum.setValue(Sportiduino.FINISH_STATION) + self._master_card_ok() + + except BaseException as err: + self._process_error(err) def CheckSt_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False: return try: - self.sportiduino.init_cp_number_card(248) - self.addText ('\nset check statnion') - except: - self.addText('\nError') + + self.addText(_translate("sportiduinopq","Write the master card to set a base station as the check station")) + self.sportiduino.init_cp_number_card(Sportiduino.CHECK_STATION) + self.sbStationNum.setValue(Sportiduino.CHECK_STATION) + self._master_card_ok() + + except BaseException as err: + self._process_error(err) def ClearSt_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False: return try: - self.sportiduino.init_cp_number_card(249) - self.addText ('\nset clear statnion') - except: - self.addText('\nError') + + self.addText(_translate("sportiduinopq","Write the master card to set a base station as the clear station")) + self.sportiduino.init_cp_number_card(Sportiduino.CLEAR_STATION) + self.sbStationNum.setValue(Sportiduino.CLEAR_STATION) + self._master_card_ok() + + except BaseException as err: + self._process_error(err) def LogCard_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False: return try: + + self.addText(_translate("sportiduinopq","Write the master card to get log of a base station")) self.sportiduino.init_backupreader() - self.addText ('\nset dump card') - except: - self.addText('\nError') + self._master_card_ok() + + except BaseException as err: + self._process_error(err) def ReadLog_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False: return - readBuffer = '' + text = "" + try: + self.addText(_translate("sportiduinopq","Read the card contained log of a base station")) + data = self.sportiduino.read_backup() - self.sportiduino.beep_ok() - try: - readBuffer += '\nread dump from CP: {}'.format(data['cp']) - except: - pass - try: - cards = data['cards'] - readBuffer += '\ntotal punches: {}\n'.format(len(cards)) - for i in range(0,len(cards),1): - readBuffer += '{},'.format(cards[i]) - except: - pass + + if data['cp'] == 0: + raise BaseException(_translate("sportiduinopq","No log data available")) + + text = _translate("sportiduinopq","Station N: {} ").format(data['cp']) + "\n" + cards = data['cards'] + + text += _translate("sportiduinopq","Total punches {}").format(len(cards)) + "\n" + + text += _translate("sportiduinopq","Cards:") + " " + + for i in range(0, len(cards), 1): + if i > 0: + text += ", " + text += "{}".format(cards[i]) + + self.addText(text) + self.dumpData.append(data) dumpFile = open(os.path.join('data','dumpData{:%Y%m%d%H%M%S}.json'.format(self.initTime)),'w') json.dump(self.dumpData, dumpFile) dumpFile.close() - self.addText(readBuffer) - except: - self.addText('\nError') + + except BaseException as err: + self._process_error(err) def SleepCard_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False: return try: - self.sportiduino.init_sleepcard() - self.addText ('\nset sleep card') - except: - self.addText('\nError') + + self.addText(_translate("sportiduinopq","Write the master card to sleep a base station")) + self.sportiduino.init_sleepcard(self.dtCompetion.dateTime().toUTC()) + self._master_card_ok() + + except BaseException as err: + self._process_error(err) def PassCard_clicked(self): - if (self.connected == False): - self.addText('\nmaster station is not connected') + if self._check_connection() == False: return + + try: - workTime = self.WorkTime.currentText() - stFi = self.StartFinish.currentText() - checkIT = self.CheckInitTime.currentText() - autoDel = self.AutoDel.currentText() - - if (workTime == '6 hour'): - a = 0b00 - elif (workTime == '24 hour'): - a = 0b01 - elif (workTime == 'not work'): - a = 0b10 - elif (workTime == 'all time'): - a = 0b11 - - if (stFi == "off"): - b = 0b0 - elif (stFi == 'on'): - b = 0b1 + self.addText(_translate("sportiduinopq","Write the master card to write new password and settings to a base station")) + setSt = self.getSettingsFromUI() - if (checkIT == 'off'): - c = 0b0 - elif (checkIT == 'on'): - c = 0b1 - - if (autoDel == 'off'): - d = 0b0 - elif (autoDel == 'on'): - d = 0b1 + oldPass = self.sbOldPwd1.value()<<16 | self.sbOldPwd2.value()<<8 | self.sbOldPwd3.value() + newPass = self.sbNewPwd1.value()<<16 | self.sbNewPwd2.value()<<8 | self.sbNewPwd3.value() + + gain = (self.cbAntennaGain.currentIndex() + 2) << 4 + + self.sportiduino.init_passwd_card(oldPass,newPass,setSt,gain) + + self.sbCurPwd3.setValue(self.sbNewPwd3.value()) + self.sbCurPwd2.setValue(self.sbNewPwd2.value()) + self.sbCurPwd1.setValue(self.sbNewPwd1.value()) + + self._master_card_ok() + + except BaseException as err: + self._process_error(err) + + def ApplyPwd_clicked(self): + if self._check_connection() == False: + return - setSt = a + ( b<<2) + (c<<3) + (d<<4) + curPass = self.sbCurPwd1.value()<<16 | self.sbCurPwd2.value()<<8 | self.sbCurPwd3.value() - if (self.OldPass.text().isdigit()): - oldPass = int(self.OldPass.text()) - if (oldPass <0 or oldPass > 10000000): - self.addText('\nnot correct old pass value') - oldPass = -1 - else: - self.addText('\nnot correct old pass value') - oldPass = -1 - - if (self.NewPass.text().isdigit()): - newPass = int(self.NewPass.text()) - if (newPass <0 or newPass > 10000000): - self.addText('\nnot correct new pass value') - newPass = -1 - else: - self.addText('\nnot correct new pass value') - newPass = -1 + try: + self.addText(_translate("sportiduinopq","Apply the current password")) + + self.sportiduino.apply_pwd(curPass) + self.addText(_translate("sportiduinopq","The password has been applied successfully")) - if (newPass!= -1 and oldPass!= -1): - try: - self.sportiduino.init_passwd_card(oldPass,newPass,setSt) - self.addText ('\nset password - settings card') - except: - self.addText('\nError') + except BaseException as err: + self._process_error(err) - def LoadSet_clicked(self): + def CreateInfo_clicked(self): + if self._check_connection() == False: + return try: - sets = open(os.path.join('data','settings.txt')) - self.WorkTime.setCurrentText(sets.readline().rstrip()) - self.StartFinish.setCurrentText(sets.readline().rstrip()) - self.CheckInitTime.setCurrentText(sets.readline().rstrip()) - self.CardCap.setCurrentText(sets.readline().rstrip()) - self.AutoDel.setCurrentText(sets.readline().rstrip()) - self.NewPass.setText(sets.readline().rstrip()) - self.OldPass.setText(sets.readline().rstrip()) - self.addText('\nload settings') - except: - self.addText('\nsettings are missing') - - def SaveSet_clicked(self): - - sets = open(os.path.join('data','settings.txt'),'w') - sets.write(self.WorkTime.currentText()+'\n') - sets.write(self.StartFinish.currentText()+'\n') - sets.write(self.CheckInitTime.currentText()+'\n') - sets.write(self.CardCap.currentText()+'\n') - sets.write(self.AutoDel.currentText()+'\n') - sets.write(self.NewPass.text()+'\n') - sets.write(self.OldPass.text()) - self.addText('\nsave settings') + + self.addText(_translate("sportiduinopq","Write the master card to get info about a base station")) + self.sportiduino.init_info_card() + self._master_card_ok() + + except BaseException as err: + self._process_error(err) + + def ReadInfo_clicked(self): + if self._check_connection() == False: + return + + try: + + self.addText(_translate("sportiduinopq","Read the card contained info about a base station")) + bs = self.sportiduino.read_info_card() + self.showBaseStationInfo(bs) + + except BaseException as err: + self._process_error(err) + + def LoadSet_clicked(self): + + self.addText("\n" + _translate("sportiduinopq","Load settings from file /data/settings.json")) + + try: + + file = open(os.path.join('data','settings.json'),'r') + + obj = json.load(file); + + file.close() + + settings = obj['settings'] + gain = obj['gain'] + pwd1 = obj['pwd1'] + pwd2 = obj['pwd2'] + pwd3 = obj['pwd3'] + + self.showSettings(settings) + + self.cbAntennaGain.setCurrentIndex(gain) + + self.sbCurPwd1.setValue(pwd1) + self.sbCurPwd2.setValue(pwd2) + self.sbCurPwd3.setValue(pwd3) + self.sbOldPwd1.setValue(pwd1) + self.sbOldPwd2.setValue(pwd2) + self.sbOldPwd3.setValue(pwd3) + + self.addText(_translate("sportiduinopq","Settings has been loaded successfully")) + self.addText(_translate("sportiduinopq","Click 'Apply Pwd' on #Settings1 tab")) + + except BaseException as err: + self._process_error(err) - def addText(self,text): + def SaveSet_clicked(self): + self.addText("\n" + _translate("sportiduinopq","Save settings to file /data/settings.json")) + + try: + + settings = self.getSettingsFromUI() + gain = self.cbAntennaGain.currentIndex() + + obj = {} + obj['settings'] = settings + obj['gain'] = gain + obj['pwd1'] = self.sbCurPwd1.value() + obj['pwd2'] = self.sbCurPwd2.value() + obj['pwd3'] = self.sbCurPwd3.value() + + file = open(os.path.join('data','settings.json'),'w') + json.dump(obj, file) + file.close() + + self.addText(_translate("sportiduinopq","Settings has been saved successfully")) + + except BaseException as err: + self._process_error(err) + def addText(self,text): + text += '\n' logFile = open(os.path.join('log','logFile{:%Y%m%d%H%M%S}.txt'.format(self.initTime)),'a') print(text) - self.textBrowser.setPlainText(text) + browserText = self.textBrowser.toPlainText() + browserText = browserText + text + self.textBrowser.setPlainText(browserText) logFile.write(text) logFile.close() def SelectPrinter_clicked(self): - dialog = QtPrintSupport.QPrintDialog() + dialog = QtPrintSupport.QPrintDialog(self.printer) if dialog.exec_() == QtWidgets.QDialog.Accepted: - printer = dialog.printer() - self.printerName.setText(QPrinter().printerName()) + self.printer = dialog.printer() + self.printerName.setText(self.printer.printerName()) def Print_clicked(self): - self.printer = QPrinter() + try: + self.printer.setFullPage(True) + self.printer.setPageMargins(3,3,3,3,QPrinter.Millimeter) + page_size = QSizeF() + page_size.setHeight(self.printer.height()) + page_size.setWidth(self.printer.width()) + self.textBrowser.document().setPageSize(page_size) + self.textBrowser.document().setDocumentMargin(0.0) + self.textBrowser.document().print_(self.printer) + except BaseException as err: + self._process_error(err) - self.printer.setFullPage(True) - self.printer.setPageMargins(3,3,3,3,QPrinter.Millimeter) - page_size = QSizeF() - page_size.setHeight(self.printer.height()) - page_size.setWidth(self.printer.width()) - self.textBrowser.document().setPageSize(page_size) - self.textBrowser.document().setDocumentMargin(0.0) - self.textBrowser.document().print_(self.printer) - - def readDataFormat(self,data): - - data = copy.deepcopy(data) + def SerialRead_clicked(self): + try: + + self.addText("\n" + _translate("sportiduinopq", "Reads info about a base station by UART")) + + port = 'COM' + self.cbUartPort.currentText() + + bs = BaseStation() + bs.readInfoBySerial(port, self.sbCurPwd1.value(), self.sbCurPwd2.value(), self.sbCurPwd3.value()) - readBuffer ='\nCard: {}'.format(data['card_number']) - print(data) + self.showBaseStationInfo(bs) + + except BaseException as err: + self._process_error(err) + - if('start' in data): - readBuffer +='\nStart: {}'.format(data['start']) + def SerialWrite_clicked(self): + + try: - if ('punches' in data): + self.addText("\n" + _translate("sportiduinopq","Writes settings ans password to a base station by UART")) + port = 'COM' + self.cbUartPort.currentText() + + oldPwd1 = self.sbOldPwd1.value() + oldPwd2 = self.sbOldPwd2.value() + oldPwd3 = self.sbOldPwd3.value() + + newPwd1 = self.sbNewPwd1.value() + newPwd2 = self.sbNewPwd2.value() + newPwd3 = self.sbNewPwd3.value() + + num = self.sbStationNumByUart.value() + sets = self.getSettingsFromUI() + wakeup = self.dtCompetion.dateTime().toUTC().toPyDateTime() + gain = (self.cbAntennaGain.currentIndex() + 2) << 4 + + bs = BaseStation() + bs.writeSettingsBySerial(port, oldPwd1, oldPwd2, oldPwd3, + newPwd1, newPwd2, newPwd3, num, sets, wakeup, gain) + + self.addText(_translate("sportiduinopq","Settings and password has been written successfully")) + + except BaseException as err: + self._process_error(err) + + def ClearText_clicked(self): + self.textBrowser.setPlainText('') + + def showCardData(self,data,card_type): + if (self.AutoPrint.checkState() != 0): + self.ClearText_clicked() + + card_name = Sportiduino.card_name(card_type) + text = card_name + "\n" + + if data['master_card_flag'] == 0xFF: + # show master card info + master_type = int2byte(data['master_card_type']) + + if master_type == Sportiduino.MASTER_CARD_GET_INFO: + text += _translate("sportiduinopq","Master card to get info about a base station") + elif master_type == Sportiduino.MASTER_CARD_SET_TIME: + text += _translate("sportiduinopq","Master card to set time of a base station") + elif master_type == Sportiduino.MASTER_CARD_SET_NUMBER: + text += _translate("sportiduinopq","Master card to set number of a base station") + elif master_type == Sportiduino.MASTER_CARD_SLEEP: + text += _translate("sportiduinopq","Master card to sleep a base station") + elif master_type == Sportiduino.MASTER_CARD_READ_DUMP: + text += _translate("sportiduinopq","Master card to get punches log of a base station") + elif master_type == Sportiduino.MASTER_CARD_SET_PASS: + text += _translate("sportiduinopq","Master card to write password and settings to a base station") + else: + text += _translate("sportiduinopq","Uninitialized card") + + else: + # show participant card info + card_number = data['card_number'] + init_time = datetime.fromtimestamp(data['init_timestamp']) punches = data['punches'] - - readBuffer +='\nCP - time' - for punch in range(0, len(punches), 1): - readBuffer += '\n{} - {:%H:%M:%S}'.format(punches[punch][0],punches[punch][1]) + + if card_number >= Sportiduino.MIN_CARD_NUM and card_number <= Sportiduino.MAX_CARD_NUM: + punches_count = 0 + + text += _translate("sportiduinopq","Participant card N{}").format(card_number) + "\n" + text += _translate("sportiduinopq","Init time {}").format(init_time) + "\n" + text += _translate("sportiduinopq","Punches (Check point - Time):") + "\n" + + for punch in punches: + punches_count += 1 - if('finish' in data): - readBuffer +='\nFinish: {}'.format(data['finish']) + cp = punch[0] + cp_time = punch[1] + + if cp == Sportiduino.START_STATION: + cp = _translate("sportiduinopq","Start") + if cp == Sportiduino.FINISH_STATION: + cp = _translate("sportiduinopq","Finish") + + text += "{} - {}\n".format(cp, cp_time) + + if punches_count == 0: + text += _translate("sportiduinopq", "No punches") + else: + text += _translate("sportiduinopq", "Total punches {}").format(punches_count) + else: + text += _translate("sportiduinopq","Uninitialized card") - self.addText(readBuffer) - if (self.AutoPrint.checkState()!= 0): + self.addText(text) + + if (self.AutoPrint.checkState() != 0): self.Print_clicked() - def saveDataJson(self,data): + def saveCardDataJson(self,data): + + if data['master_card_flag'] == 255: + return + + card_number = data['card_number'] + + if card_number < Sportiduino.MIN_CARD_NUM or card_number > Sportiduino.MAX_CARD_NUM: + return + if('start' in data): data['start'] = int(data['start'].timestamp()) @@ -408,6 +595,9 @@ def saveDataJson(self,data): bufferPunch.append(kort) data['punches']=bufferPunch + del data['master_card_flag'] + del data['master_card_type'] + del data['init_timestamp'] del data['page6'] del data['page7'] @@ -415,8 +605,124 @@ def saveDataJson(self,data): dataFile = open(os.path.join('data','readData{:%Y%m%d%H%M%S}.json'.format(self.initTime)),'w') json.dump(self.readData, dataFile) - dataFile.close() + dataFile.close() + + def showSettings(self, settings): + set1 = settings & 0x3 + self.WorkTime.setCurrentIndex(set1) + + set2 = (settings & 0x4) >> 0x2 + self.StartFinish.setCurrentIndex(set2) + + set3 = (settings & 0x8) >> 0x3 + self.CheckInitTime.setCurrentIndex(set3) + + set4 = (settings & 0x10) >> 0x4 + self.AutoDel.setCurrentIndex(set4) + + set5 = (settings & 0x20) >> 0x5 + self.cbFastMark.setCurrentIndex(set5) + + def getSettingsFromUI(self): + workTime = self.WorkTime.currentIndex() + stFi = self.StartFinish.currentIndex() + checkIT = self.CheckInitTime.currentIndex() + autoDel = self.AutoDel.currentIndex() + fastMark = self.cbFastMark.currentIndex() + + if (workTime == 0): + a = 0b00 + elif (workTime == 1): + a = 0b01 + elif (workTime == 2): + a = 0b10 + elif (workTime == 3): + a = 0b11 + + if (stFi == 0): + b = 0b0 + elif (stFi == 1): + b = 0b1 + + if (checkIT == 0): + c = 0b0 + elif (checkIT == 1): + c = 0b1 + + if (autoDel == 0): + d = 0b0 + elif (autoDel == 1): + d = 0b1 + + if (fastMark == 0): + e = 0b0 + elif (fastMark == 1): + e = 0b1 + + setSt = a + ( b<<2) + (c<<3) + (d<<4) + (e<<5) + + return setSt + + def showBaseStationInfo(self, bs): + self.addText(_translate("sportiduinopq","Version: {}.{}.{}").format(bs.hwVers(), bs.fwMajorVers(), bs.fwMinorVers())) + text = _translate("sportiduinopq","Station N: {} ").format(bs.num) + + if(bs.num == BaseStation.START_STATION_NUM): + text += _translate("sportiduinopq","(Start)") + elif (bs.num == BaseStation.FINISH_STATION_NUM): + text += _translate("sportiduinopq","(Finish)") + elif (bs.num == BaseStation.CHECK_STATION_NUM): + text += _translate("sportiduinopq","(Check)") + elif (bs.num == BaseStation.CLEAR_STATION_NUM): + text += _translate("sportiduinopq","(Clear)") + + self.addText(text) + + text = _translate("sportiduinopq","Settings: {}").format(bin(bs.settings).lstrip('-0b').zfill(8)) + self.addText(text) + + if(bs.batteryOk): + self.addText(_translate("sportiduinopq","Battery: OK")) + else: + self.addText(_translate("sportiduinopq","Battery: Low")) + + if(bs.mode == BaseStation.MODE_ACTIVE): + self.addText(_translate("sportiduinopq","Mode: Active")) + elif(bs.mode == BaseStation.MODE_WAIT): + self.addText(_translate("sportiduinopq","Mode: Wait")) + elif(bs.mode == BaseStation.MODE_SLEEP): + self.addText(_translate("sportiduinopq","Mode: Sleep")) + + text = _translate("sportiduinopq", "Clock: {}").format(datetime.fromtimestamp(bs.timestamp)) + self.addText(text) + text = _translate("sportiduinopq", "Alarm: {}").format(datetime.fromtimestamp(bs.wakeup)) + self.addText(text) + + idx = (bs.antennaGain >> 4) - 2; + self.cbAntennaGain.setCurrentIndex(idx) + self.addText(_translate("sportiduinopq","Antenna Gain: {}").format(self.cbAntennaGain.currentText())) + + # apply settings to ui + self.sbStationNum.setValue(bs.num) + self.sbStationNumByUart.setValue(bs.num) + self.dtCompetion.setDateTime(datetime.fromtimestamp(bs.wakeup)) + self.showSettings(bs.settings) + + self.addText(_translate("sportiduinopq","Settings displayed by UI has been chaged to the base station settings")) + + def _process_error(self, err): + self.addText(_translate("sportiduinopq","Error: {}").format(err)) + + def _check_connection(self): + self.addText("") + if self.connected == False: + self.addText(_translate("sportiduinopq","Master station is not connected")) + return False + return True + + def _master_card_ok(self): + self.addText(_translate("sportiduinopq","The master card has been written successfully")) if __name__ == '__main__': @@ -427,6 +733,12 @@ def saveDataJson(self,data): pass app = QtWidgets.QApplication(sys.argv) + + translator = QTranslator() + translator.load("sportiduinopq_" + QLocale.system().name(), "./translation") + if not app.installTranslator(translator): + print("Can not install translation!") + window = App() window.show() app.exec_() diff --git a/design.py b/design.py index 69961c4..c1c793d 100644 --- a/design.py +++ b/design.py @@ -11,7 +11,8 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(408, 453) + MainWindow.resize(530, 703) + MainWindow.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.centralwidget) @@ -21,15 +22,23 @@ def setupUi(self, MainWindow): self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.Connec = QtWidgets.QPushButton(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.Connec.sizePolicy().hasHeightForWidth()) + self.Connec.setSizePolicy(sizePolicy) + self.Connec.setMaximumSize(QtCore.QSize(75, 16777215)) font = QtGui.QFont() font.setPointSize(12) self.Connec.setFont(font) + self.Connec.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.Connec.setObjectName("Connec") self.horizontalLayout.addWidget(self.Connec) self.label_8 = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(12) self.label_8.setFont(font) + self.label_8.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.label_8.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.label_8.setObjectName("label_8") self.horizontalLayout.addWidget(self.label_8) @@ -37,6 +46,7 @@ def setupUi(self, MainWindow): font = QtGui.QFont() font.setPointSize(12) self.choiseCom.setFont(font) + self.choiseCom.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.choiseCom.setObjectName("choiseCom") self.choiseCom.addItem("") self.choiseCom.addItem("") @@ -74,10 +84,18 @@ def setupUi(self, MainWindow): self.horizontalLayout.addWidget(self.choiseCom) self.verticalLayout.addLayout(self.horizontalLayout) self.Log = QtWidgets.QTabWidget(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.Log.sizePolicy().hasHeightForWidth()) + self.Log.setSizePolicy(sizePolicy) + self.Log.setMinimumSize(QtCore.QSize(0, 0)) + self.Log.setMaximumSize(QtCore.QSize(16777215, 16777215)) font = QtGui.QFont() font.setPointSize(12) self.Log.setFont(font) self.Log.setToolTipDuration(-3) + self.Log.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.Log.setObjectName("Log") self.tab_4 = QtWidgets.QWidget() self.tab_4.setObjectName("tab_4") @@ -88,99 +106,157 @@ def setupUi(self, MainWindow): self.SelectPrinter.setGeometry(QtCore.QRect(10, 170, 111, 31)) self.SelectPrinter.setObjectName("SelectPrinter") self.ReadCard = QtWidgets.QPushButton(self.tab_4) - self.ReadCard.setGeometry(QtCore.QRect(10, 10, 181, 61)) + self.ReadCard.setGeometry(QtCore.QRect(10, 10, 191, 61)) self.ReadCard.setObjectName("ReadCard") self.AutoPrint = QtWidgets.QCheckBox(self.tab_4) self.AutoPrint.setGeometry(QtCore.QRect(10, 210, 121, 31)) self.AutoPrint.setObjectName("AutoPrint") self.printerName = QtWidgets.QLabel(self.tab_4) - self.printerName.setGeometry(QtCore.QRect(10, 140, 141, 41)) + self.printerName.setGeometry(QtCore.QRect(10, 140, 111, 31)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.printerName.sizePolicy().hasHeightForWidth()) + self.printerName.setSizePolicy(sizePolicy) self.printerName.setText("") self.printerName.setObjectName("printerName") self.line_8 = QtWidgets.QFrame(self.tab_4) - self.line_8.setGeometry(QtCore.QRect(0, 80, 211, 20)) + self.line_8.setGeometry(QtCore.QRect(10, 80, 191, 20)) self.line_8.setFrameShape(QtWidgets.QFrame.HLine) self.line_8.setFrameShadow(QtWidgets.QFrame.Sunken) self.line_8.setObjectName("line_8") self.line_10 = QtWidgets.QFrame(self.tab_4) - self.line_10.setGeometry(QtCore.QRect(0, 240, 211, 20)) + self.line_10.setGeometry(QtCore.QRect(10, 240, 191, 20)) self.line_10.setFrameShape(QtWidgets.QFrame.HLine) self.line_10.setFrameShadow(QtWidgets.QFrame.Sunken) self.line_10.setObjectName("line_10") - self.Log.addTab(self.tab_4, "") - self.tab = QtWidgets.QWidget() - self.tab.setObjectName("tab") - self.InitCard = QtWidgets.QPushButton(self.tab) - self.InitCard.setGeometry(QtCore.QRect(10, 70, 171, 61)) + self.InitCard = QtWidgets.QPushButton(self.tab_4) + self.InitCard.setGeometry(QtCore.QRect(10, 320, 191, 61)) self.InitCard.setObjectName("InitCard") - self.cardLine = QtWidgets.QLineEdit(self.tab) - self.cardLine.setGeometry(QtCore.QRect(10, 10, 171, 51)) - self.cardLine.setObjectName("cardLine") - self.AutoIncriment = QtWidgets.QCheckBox(self.tab) - self.AutoIncriment.setGeometry(QtCore.QRect(10, 140, 151, 31)) + self.AutoIncriment = QtWidgets.QCheckBox(self.tab_4) + self.AutoIncriment.setGeometry(QtCore.QRect(10, 390, 151, 31)) self.AutoIncriment.setObjectName("AutoIncriment") - self.Log.addTab(self.tab, "") + self.cardLine = QtWidgets.QLineEdit(self.tab_4) + self.cardLine.setGeometry(QtCore.QRect(10, 270, 191, 41)) + self.cardLine.setObjectName("cardLine") + self.Log.addTab(self.tab_4, "") self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName("tab_2") - self.SetNum = QtWidgets.QPushButton(self.tab_2) - self.SetNum.setGeometry(QtCore.QRect(10, 110, 91, 31)) + self.groupBox = QtWidgets.QGroupBox(self.tab_2) + self.groupBox.setGeometry(QtCore.QRect(10, 410, 191, 131)) + self.groupBox.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.groupBox.setObjectName("groupBox") + self.SleepCard = QtWidgets.QPushButton(self.groupBox) + self.SleepCard.setGeometry(QtCore.QRect(100, 90, 81, 31)) + self.SleepCard.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.SleepCard.setObjectName("SleepCard") + self.dtCompetion = QtWidgets.QDateTimeEdit(self.groupBox) + self.dtCompetion.setGeometry(QtCore.QRect(10, 50, 171, 31)) + self.dtCompetion.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.dtCompetion.setMinimumDate(QtCore.QDate(2017, 12, 31)) + self.dtCompetion.setCalendarPopup(True) + self.dtCompetion.setObjectName("dtCompetion") + self.label_4 = QtWidgets.QLabel(self.groupBox) + self.label_4.setGeometry(QtCore.QRect(10, 20, 171, 20)) + self.label_4.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.label_4.setObjectName("label_4") + self.groupBox_2 = QtWidgets.QGroupBox(self.tab_2) + self.groupBox_2.setGeometry(QtCore.QRect(10, 540, 191, 71)) + self.groupBox_2.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.groupBox_2.setObjectName("groupBox_2") + self.ReadLog = QtWidgets.QPushButton(self.groupBox_2) + self.ReadLog.setGeometry(QtCore.QRect(10, 30, 81, 31)) + font = QtGui.QFont() + font.setPointSize(12) + self.ReadLog.setFont(font) + self.ReadLog.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.ReadLog.setObjectName("ReadLog") + self.LogCard = QtWidgets.QPushButton(self.groupBox_2) + self.LogCard.setGeometry(QtCore.QRect(100, 30, 81, 31)) + self.LogCard.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.LogCard.setObjectName("LogCard") + self.groupBox_3 = QtWidgets.QGroupBox(self.tab_2) + self.groupBox_3.setGeometry(QtCore.QRect(10, 260, 191, 151)) + self.groupBox_3.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.groupBox_3.setObjectName("groupBox_3") + self.SetNum = QtWidgets.QPushButton(self.groupBox_3) + self.SetNum.setGeometry(QtCore.QRect(100, 30, 81, 31)) + self.SetNum.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.SetNum.setObjectName("SetNum") - self.StationLine = QtWidgets.QLineEdit(self.tab_2) - self.StationLine.setGeometry(QtCore.QRect(10, 70, 91, 31)) - self.StationLine.setObjectName("StationLine") - self.SetStart = QtWidgets.QPushButton(self.tab_2) - self.SetStart.setGeometry(QtCore.QRect(110, 70, 91, 31)) + self.SetStart = QtWidgets.QPushButton(self.groupBox_3) + self.SetStart.setGeometry(QtCore.QRect(10, 70, 81, 31)) + self.SetStart.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.SetStart.setObjectName("SetStart") - self.SetFinish = QtWidgets.QPushButton(self.tab_2) - self.SetFinish.setGeometry(QtCore.QRect(110, 110, 91, 31)) + self.SetFinish = QtWidgets.QPushButton(self.groupBox_3) + self.SetFinish.setGeometry(QtCore.QRect(100, 70, 81, 31)) + self.SetFinish.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.SetFinish.setObjectName("SetFinish") - self.ClearSt = QtWidgets.QPushButton(self.tab_2) - self.ClearSt.setGeometry(QtCore.QRect(10, 170, 91, 31)) - font = QtGui.QFont() - font.setPointSize(12) - self.ClearSt.setFont(font) - self.ClearSt.setObjectName("ClearSt") - self.CheckSt = QtWidgets.QPushButton(self.tab_2) - self.CheckSt.setGeometry(QtCore.QRect(110, 170, 91, 31)) + self.CheckSt = QtWidgets.QPushButton(self.groupBox_3) + self.CheckSt.setGeometry(QtCore.QRect(100, 110, 81, 31)) font = QtGui.QFont() font.setPointSize(12) self.CheckSt.setFont(font) + self.CheckSt.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.CheckSt.setObjectName("CheckSt") - self.LogCard = QtWidgets.QPushButton(self.tab_2) - self.LogCard.setGeometry(QtCore.QRect(10, 230, 91, 31)) - self.LogCard.setObjectName("LogCard") - self.SetTime = QtWidgets.QPushButton(self.tab_2) - self.SetTime.setGeometry(QtCore.QRect(10, 10, 91, 31)) - self.SetTime.setObjectName("SetTime") - self.ReadLog = QtWidgets.QPushButton(self.tab_2) - self.ReadLog.setGeometry(QtCore.QRect(110, 230, 91, 31)) + self.ClearSt = QtWidgets.QPushButton(self.groupBox_3) + self.ClearSt.setGeometry(QtCore.QRect(10, 110, 81, 31)) font = QtGui.QFont() font.setPointSize(12) - self.ReadLog.setFont(font) - self.ReadLog.setObjectName("ReadLog") - self.SleepCard = QtWidgets.QPushButton(self.tab_2) - self.SleepCard.setGeometry(QtCore.QRect(10, 290, 91, 31)) - self.SleepCard.setObjectName("SleepCard") - self.line_2 = QtWidgets.QFrame(self.tab_2) - self.line_2.setGeometry(QtCore.QRect(-3, 30, 211, 41)) - self.line_2.setFrameShape(QtWidgets.QFrame.HLine) - self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) - self.line_2.setObjectName("line_2") - self.line_3 = QtWidgets.QFrame(self.tab_2) - self.line_3.setGeometry(QtCore.QRect(0, 140, 211, 31)) - self.line_3.setFrameShape(QtWidgets.QFrame.HLine) - self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken) - self.line_3.setObjectName("line_3") - self.line_4 = QtWidgets.QFrame(self.tab_2) - self.line_4.setGeometry(QtCore.QRect(-3, 199, 211, 31)) - self.line_4.setFrameShape(QtWidgets.QFrame.HLine) - self.line_4.setFrameShadow(QtWidgets.QFrame.Sunken) - self.line_4.setObjectName("line_4") - self.line_5 = QtWidgets.QFrame(self.tab_2) - self.line_5.setGeometry(QtCore.QRect(-3, 259, 211, 31)) - self.line_5.setFrameShape(QtWidgets.QFrame.HLine) - self.line_5.setFrameShadow(QtWidgets.QFrame.Sunken) - self.line_5.setObjectName("line_5") + self.ClearSt.setFont(font) + self.ClearSt.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.ClearSt.setObjectName("ClearSt") + self.sbStationNum = QtWidgets.QSpinBox(self.groupBox_3) + self.sbStationNum.setGeometry(QtCore.QRect(10, 30, 81, 31)) + self.sbStationNum.setFrame(True) + self.sbStationNum.setAlignment(QtCore.Qt.AlignCenter) + self.sbStationNum.setMinimum(1) + self.sbStationNum.setMaximum(255) + self.sbStationNum.setObjectName("sbStationNum") + self.groupBox_4 = QtWidgets.QGroupBox(self.tab_2) + self.groupBox_4.setGeometry(QtCore.QRect(10, 120, 191, 71)) + self.groupBox_4.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.groupBox_4.setObjectName("groupBox_4") + self.SetTime = QtWidgets.QPushButton(self.groupBox_4) + self.SetTime.setGeometry(QtCore.QRect(100, 30, 81, 31)) + self.SetTime.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.SetTime.setObjectName("SetTime") + self.groupBox_5 = QtWidgets.QGroupBox(self.tab_2) + self.groupBox_5.setGeometry(QtCore.QRect(10, 190, 191, 71)) + self.groupBox_5.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.groupBox_5.setObjectName("groupBox_5") + self.btnCreateInfoCard = QtWidgets.QPushButton(self.groupBox_5) + self.btnCreateInfoCard.setGeometry(QtCore.QRect(100, 30, 81, 31)) + self.btnCreateInfoCard.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.btnCreateInfoCard.setObjectName("btnCreateInfoCard") + self.btnReadInfo = QtWidgets.QPushButton(self.groupBox_5) + self.btnReadInfo.setGeometry(QtCore.QRect(10, 30, 81, 31)) + self.btnReadInfo.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.btnReadInfo.setObjectName("btnReadInfo") + self.groupBox_6 = QtWidgets.QGroupBox(self.tab_2) + self.groupBox_6.setGeometry(QtCore.QRect(9, 10, 191, 111)) + self.groupBox_6.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.groupBox_6.setObjectName("groupBox_6") + self.btnApplyPwd = QtWidgets.QPushButton(self.groupBox_6) + self.btnApplyPwd.setGeometry(QtCore.QRect(100, 70, 81, 31)) + self.btnApplyPwd.setObjectName("btnApplyPwd") + self.sbCurPwd3 = QtWidgets.QSpinBox(self.groupBox_6) + self.sbCurPwd3.setGeometry(QtCore.QRect(10, 30, 51, 31)) + self.sbCurPwd3.setFrame(True) + self.sbCurPwd3.setAlignment(QtCore.Qt.AlignCenter) + self.sbCurPwd3.setMaximum(255) + self.sbCurPwd3.setObjectName("sbCurPwd3") + self.sbCurPwd2 = QtWidgets.QSpinBox(self.groupBox_6) + self.sbCurPwd2.setGeometry(QtCore.QRect(70, 30, 51, 31)) + self.sbCurPwd2.setFrame(True) + self.sbCurPwd2.setAlignment(QtCore.Qt.AlignCenter) + self.sbCurPwd2.setMaximum(255) + self.sbCurPwd2.setObjectName("sbCurPwd2") + self.sbCurPwd1 = QtWidgets.QSpinBox(self.groupBox_6) + self.sbCurPwd1.setGeometry(QtCore.QRect(130, 30, 51, 31)) + self.sbCurPwd1.setFrame(True) + self.sbCurPwd1.setAlignment(QtCore.Qt.AlignCenter) + self.sbCurPwd1.setMaximum(255) + self.sbCurPwd1.setObjectName("sbCurPwd1") self.Log.addTab(self.tab_2, "") self.tab_3 = QtWidgets.QWidget() self.tab_3.setObjectName("tab_3") @@ -193,7 +269,7 @@ def setupUi(self, MainWindow): self.WorkTime.addItem("") self.WorkTime.addItem("") self.label = QtWidgets.QLabel(self.tab_3) - self.label.setGeometry(QtCore.QRect(10, 10, 91, 31)) + self.label.setGeometry(QtCore.QRect(10, 10, 111, 31)) self.label.setObjectName("label") self.label_2 = QtWidgets.QLabel(self.tab_3) self.label_2.setGeometry(QtCore.QRect(10, 50, 111, 31)) @@ -205,7 +281,7 @@ def setupUi(self, MainWindow): self.StartFinish.addItem("") self.StartFinish.addItem("") self.label_3 = QtWidgets.QLabel(self.tab_3) - self.label_3.setGeometry(QtCore.QRect(10, 90, 131, 41)) + self.label_3.setGeometry(QtCore.QRect(10, 90, 111, 31)) self.label_3.setObjectName("label_3") self.CheckInitTime = QtWidgets.QComboBox(self.tab_3) self.CheckInitTime.setGeometry(QtCore.QRect(130, 90, 71, 31)) @@ -214,7 +290,7 @@ def setupUi(self, MainWindow): self.CheckInitTime.addItem("") self.CheckInitTime.addItem("") self.label_5 = QtWidgets.QLabel(self.tab_3) - self.label_5.setGeometry(QtCore.QRect(10, 130, 111, 41)) + self.label_5.setGeometry(QtCore.QRect(10, 130, 111, 31)) self.label_5.setObjectName("label_5") self.AutoDel = QtWidgets.QComboBox(self.tab_3) self.AutoDel.setGeometry(QtCore.QRect(130, 130, 71, 31)) @@ -222,34 +298,170 @@ def setupUi(self, MainWindow): self.AutoDel.setObjectName("AutoDel") self.AutoDel.addItem("") self.AutoDel.addItem("") - self.label_6 = QtWidgets.QLabel(self.tab_3) - self.label_6.setGeometry(QtCore.QRect(10, 190, 81, 41)) - self.label_6.setObjectName("label_6") - self.label_7 = QtWidgets.QLabel(self.tab_3) - self.label_7.setGeometry(QtCore.QRect(10, 230, 81, 41)) - self.label_7.setObjectName("label_7") - self.NewPass = QtWidgets.QLineEdit(self.tab_3) - self.NewPass.setGeometry(QtCore.QRect(100, 190, 101, 31)) - self.NewPass.setObjectName("NewPass") - self.OldPass = QtWidgets.QLineEdit(self.tab_3) - self.OldPass.setGeometry(QtCore.QRect(100, 230, 101, 31)) - self.OldPass.setObjectName("OldPass") self.PassCard = QtWidgets.QPushButton(self.tab_3) - self.PassCard.setGeometry(QtCore.QRect(10, 290, 191, 31)) + self.PassCard.setGeometry(QtCore.QRect(10, 390, 191, 31)) self.PassCard.setObjectName("PassCard") self.SaveSet = QtWidgets.QPushButton(self.tab_3) - self.SaveSet.setGeometry(QtCore.QRect(110, 330, 91, 31)) + self.SaveSet.setGeometry(QtCore.QRect(110, 430, 91, 31)) self.SaveSet.setObjectName("SaveSet") self.LoadSet = QtWidgets.QPushButton(self.tab_3) - self.LoadSet.setGeometry(QtCore.QRect(10, 330, 91, 31)) + self.LoadSet.setGeometry(QtCore.QRect(10, 430, 91, 31)) self.LoadSet.setObjectName("LoadSet") + self.groupBox_7 = QtWidgets.QGroupBox(self.tab_3) + self.groupBox_7.setGeometry(QtCore.QRect(10, 240, 191, 71)) + self.groupBox_7.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.groupBox_7.setObjectName("groupBox_7") + self.sbNewPwd3 = QtWidgets.QSpinBox(self.groupBox_7) + self.sbNewPwd3.setGeometry(QtCore.QRect(10, 30, 51, 31)) + self.sbNewPwd3.setFrame(True) + self.sbNewPwd3.setAlignment(QtCore.Qt.AlignCenter) + self.sbNewPwd3.setMaximum(255) + self.sbNewPwd3.setObjectName("sbNewPwd3") + self.sbNewPwd2 = QtWidgets.QSpinBox(self.groupBox_7) + self.sbNewPwd2.setGeometry(QtCore.QRect(70, 30, 51, 31)) + self.sbNewPwd2.setFrame(True) + self.sbNewPwd2.setAlignment(QtCore.Qt.AlignCenter) + self.sbNewPwd2.setMaximum(255) + self.sbNewPwd2.setObjectName("sbNewPwd2") + self.sbNewPwd1 = QtWidgets.QSpinBox(self.groupBox_7) + self.sbNewPwd1.setGeometry(QtCore.QRect(130, 30, 51, 31)) + self.sbNewPwd1.setFrame(True) + self.sbNewPwd1.setAlignment(QtCore.Qt.AlignCenter) + self.sbNewPwd1.setMaximum(255) + self.sbNewPwd1.setObjectName("sbNewPwd1") + self.groupBox_8 = QtWidgets.QGroupBox(self.tab_3) + self.groupBox_8.setGeometry(QtCore.QRect(10, 310, 191, 71)) + self.groupBox_8.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.groupBox_8.setObjectName("groupBox_8") + self.sbOldPwd3 = QtWidgets.QSpinBox(self.groupBox_8) + self.sbOldPwd3.setGeometry(QtCore.QRect(10, 30, 51, 31)) + self.sbOldPwd3.setFrame(True) + self.sbOldPwd3.setAlignment(QtCore.Qt.AlignCenter) + self.sbOldPwd3.setMaximum(255) + self.sbOldPwd3.setObjectName("sbOldPwd3") + self.sbOldPwd2 = QtWidgets.QSpinBox(self.groupBox_8) + self.sbOldPwd2.setGeometry(QtCore.QRect(70, 30, 51, 31)) + self.sbOldPwd2.setFrame(True) + self.sbOldPwd2.setAlignment(QtCore.Qt.AlignCenter) + self.sbOldPwd2.setMaximum(255) + self.sbOldPwd2.setObjectName("sbOldPwd2") + self.sbOldPwd1 = QtWidgets.QSpinBox(self.groupBox_8) + self.sbOldPwd1.setGeometry(QtCore.QRect(130, 30, 51, 31)) + self.sbOldPwd1.setFrame(True) + self.sbOldPwd1.setAlignment(QtCore.Qt.AlignCenter) + self.sbOldPwd1.setMaximum(255) + self.sbOldPwd1.setObjectName("sbOldPwd1") + self.groupBox_9 = QtWidgets.QGroupBox(self.tab_3) + self.groupBox_9.setGeometry(QtCore.QRect(10, 460, 191, 151)) + self.groupBox_9.setObjectName("groupBox_9") + self.cbUartPort = QtWidgets.QComboBox(self.groupBox_9) + self.cbUartPort.setGeometry(QtCore.QRect(120, 30, 61, 31)) + font = QtGui.QFont() + font.setPointSize(12) + self.cbUartPort.setFont(font) + self.cbUartPort.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.cbUartPort.setObjectName("cbUartPort") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.cbUartPort.addItem("") + self.label_9 = QtWidgets.QLabel(self.groupBox_9) + self.label_9.setGeometry(QtCore.QRect(10, 30, 81, 31)) + font = QtGui.QFont() + font.setPointSize(12) + self.label_9.setFont(font) + self.label_9.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.label_9.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.label_9.setObjectName("label_9") + self.label_10 = QtWidgets.QLabel(self.groupBox_9) + self.label_10.setGeometry(QtCore.QRect(10, 70, 101, 31)) + font = QtGui.QFont() + font.setPointSize(12) + self.label_10.setFont(font) + self.label_10.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) + self.label_10.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.label_10.setObjectName("label_10") + self.btnUartRead = QtWidgets.QPushButton(self.groupBox_9) + self.btnUartRead.setGeometry(QtCore.QRect(10, 110, 81, 31)) + self.btnUartRead.setObjectName("btnUartRead") + self.btnUartWrite = QtWidgets.QPushButton(self.groupBox_9) + self.btnUartWrite.setGeometry(QtCore.QRect(100, 110, 81, 31)) + self.btnUartWrite.setObjectName("btnUartWrite") + self.sbStationNumByUart = QtWidgets.QSpinBox(self.groupBox_9) + self.sbStationNumByUart.setGeometry(QtCore.QRect(120, 70, 61, 31)) + self.sbStationNumByUart.setFrame(True) + self.sbStationNumByUart.setAlignment(QtCore.Qt.AlignCenter) + self.sbStationNumByUart.setMinimum(1) + self.sbStationNumByUart.setMaximum(255) + self.sbStationNumByUart.setObjectName("sbStationNumByUart") + self.label_6 = QtWidgets.QLabel(self.tab_3) + self.label_6.setGeometry(QtCore.QRect(10, 170, 111, 31)) + self.label_6.setObjectName("label_6") + self.cbFastMark = QtWidgets.QComboBox(self.tab_3) + self.cbFastMark.setGeometry(QtCore.QRect(130, 170, 71, 31)) + self.cbFastMark.setEditable(False) + self.cbFastMark.setObjectName("cbFastMark") + self.cbFastMark.addItem("") + self.cbFastMark.addItem("") + self.cbAntennaGain = QtWidgets.QComboBox(self.tab_3) + self.cbAntennaGain.setGeometry(QtCore.QRect(130, 210, 71, 31)) + self.cbAntennaGain.setEditable(False) + self.cbAntennaGain.setObjectName("cbAntennaGain") + self.cbAntennaGain.addItem("") + self.cbAntennaGain.addItem("") + self.cbAntennaGain.addItem("") + self.cbAntennaGain.addItem("") + self.cbAntennaGain.addItem("") + self.cbAntennaGain.addItem("") + self.label_7 = QtWidgets.QLabel(self.tab_3) + self.label_7.setGeometry(QtCore.QRect(10, 210, 111, 31)) + self.label_7.setObjectName("label_7") self.Log.addTab(self.tab_3, "") self.verticalLayout.addWidget(self.Log) self.horizontalLayout_4.addLayout(self.verticalLayout) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) + self.verticalLayout_2.setObjectName("verticalLayout_2") self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget) + self.textBrowser.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.textBrowser.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.textBrowser.setObjectName("textBrowser") - self.horizontalLayout_4.addWidget(self.textBrowser) + self.verticalLayout_2.addWidget(self.textBrowser) + self.btnClearText = QtWidgets.QPushButton(self.centralwidget) + font = QtGui.QFont() + font.setPointSize(12) + self.btnClearText.setFont(font) + self.btnClearText.setObjectName("btnClearText") + self.verticalLayout_2.addWidget(self.btnClearText) + self.horizontalLayout_4.addLayout(self.verticalLayout_2) MainWindow.setCentralWidget(self.centralwidget) self.actionConnect = QtWidgets.QAction(MainWindow) self.actionConnect.setObjectName("actionConnect") @@ -262,15 +474,13 @@ def setupUi(self, MainWindow): self.retranslateUi(MainWindow) self.Log.setCurrentIndex(0) + self.cbUartPort.setCurrentIndex(0) + self.cbAntennaGain.setCurrentIndex(5) QtCore.QMetaObject.connectSlotsByName(MainWindow) MainWindow.setTabOrder(self.Connec, self.choiseCom) MainWindow.setTabOrder(self.choiseCom, self.Log) - MainWindow.setTabOrder(self.Log, self.cardLine) - MainWindow.setTabOrder(self.cardLine, self.InitCard) - MainWindow.setTabOrder(self.InitCard, self.AutoIncriment) - MainWindow.setTabOrder(self.AutoIncriment, self.SetTime) - MainWindow.setTabOrder(self.SetTime, self.StationLine) - MainWindow.setTabOrder(self.StationLine, self.SetNum) + MainWindow.setTabOrder(self.Log, self.SetTime) + MainWindow.setTabOrder(self.SetTime, self.SetNum) MainWindow.setTabOrder(self.SetNum, self.SetStart) MainWindow.setTabOrder(self.SetStart, self.SetFinish) MainWindow.setTabOrder(self.SetFinish, self.ClearSt) @@ -282,12 +492,9 @@ def setupUi(self, MainWindow): MainWindow.setTabOrder(self.WorkTime, self.StartFinish) MainWindow.setTabOrder(self.StartFinish, self.CheckInitTime) MainWindow.setTabOrder(self.CheckInitTime, self.AutoDel) - MainWindow.setTabOrder(self.AutoDel, self.NewPass) - MainWindow.setTabOrder(self.NewPass, self.OldPass) - MainWindow.setTabOrder(self.OldPass, self.PassCard) + MainWindow.setTabOrder(self.AutoDel, self.PassCard) MainWindow.setTabOrder(self.PassCard, self.LoadSet) MainWindow.setTabOrder(self.LoadSet, self.SaveSet) - MainWindow.setTabOrder(self.SaveSet, self.textBrowser) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate @@ -329,42 +536,123 @@ def retranslateUi(self, MainWindow): self.choiseCom.setItemText(32, _translate("MainWindow", "31")) self.Print.setText(_translate("MainWindow", "Print")) self.SelectPrinter.setText(_translate("MainWindow", "Select Printer")) + self.ReadCard.setToolTip(_translate("MainWindow", "Reads a participant card")) self.ReadCard.setText(_translate("MainWindow", "Read Card")) self.AutoPrint.setText(_translate("MainWindow", "AutoPrint")) - self.Log.setTabText(self.Log.indexOf(self.tab_4), _translate("MainWindow", "Read")) + self.InitCard.setToolTip(_translate("MainWindow", "Inits a participant card")) self.InitCard.setText(_translate("MainWindow", "Init Card")) self.AutoIncriment.setText(_translate("MainWindow", "AutoIncriment")) - self.Log.setTabText(self.Log.indexOf(self.tab), _translate("MainWindow", "Card")) - self.SetNum.setText(_translate("MainWindow", "Set Number")) + self.Log.setTabText(self.Log.indexOf(self.tab_4), _translate("MainWindow", "Main")) + self.groupBox.setTitle(_translate("MainWindow", "Sleep Card")) + self.SleepCard.setToolTip(_translate("MainWindow", "Creates the master card to force a base station to sleep and to wake-up at competion date")) + self.SleepCard.setText(_translate("MainWindow", "Create")) + self.dtCompetion.setDisplayFormat(_translate("MainWindow", "dd.MM.yyyy HH:mm")) + self.label_4.setText(_translate("MainWindow", "Competion Date/Time")) + self.groupBox_2.setTitle(_translate("MainWindow", "Dump Card")) + self.ReadLog.setToolTip(_translate("MainWindow", "Reads the card contained punches log of a base station")) + self.ReadLog.setText(_translate("MainWindow", "Read")) + self.LogCard.setToolTip(_translate("MainWindow", "Creates the master card to read punches log of a base station")) + self.LogCard.setText(_translate("MainWindow", "Create")) + self.groupBox_3.setTitle(_translate("MainWindow", "StationNum Card")) + self.SetNum.setToolTip(_translate("MainWindow", "Creates the master card to set number of a base station")) + self.SetNum.setText(_translate("MainWindow", "Set Num")) + self.SetStart.setToolTip(_translate("MainWindow", "Creates the master card to make a base station as a start station")) self.SetStart.setText(_translate("MainWindow", "Set Start")) + self.SetFinish.setToolTip(_translate("MainWindow", "Creates the master card to make a base station as a finish station")) self.SetFinish.setText(_translate("MainWindow", "Set Finish")) - self.ClearSt.setText(_translate("MainWindow", "Clear St")) + self.CheckSt.setToolTip(_translate("MainWindow", "Creates the master card to make a base station as a check station")) self.CheckSt.setText(_translate("MainWindow", "Check St")) - self.LogCard.setText(_translate("MainWindow", "Dump Card")) - self.SetTime.setText(_translate("MainWindow", "Set Time")) - self.ReadLog.setText(_translate("MainWindow", "Read Dump")) - self.SleepCard.setText(_translate("MainWindow", "Sleep Card")) - self.Log.setTabText(self.Log.indexOf(self.tab_2), _translate("MainWindow", "St")) + self.ClearSt.setToolTip(_translate("MainWindow", "Creates the master card to make a base station as a clear station")) + self.ClearSt.setText(_translate("MainWindow", "Clear St")) + self.groupBox_4.setTitle(_translate("MainWindow", "Date/Time Card")) + self.SetTime.setToolTip(_translate("MainWindow", "Creates the master card to set clock of a base station")) + self.SetTime.setText(_translate("MainWindow", "Create")) + self.groupBox_5.setTitle(_translate("MainWindow", "Status Card")) + self.btnCreateInfoCard.setToolTip(_translate("MainWindow", "Creates the master card to get info about a base station")) + self.btnCreateInfoCard.setText(_translate("MainWindow", "Create")) + self.btnReadInfo.setToolTip(_translate("MainWindow", "Reads the card contained info about a base station")) + self.btnReadInfo.setText(_translate("MainWindow", "Read")) + self.groupBox_6.setToolTip(_translate("MainWindow", "Current password of a base station")) + self.groupBox_6.setTitle(_translate("MainWindow", "Password")) + self.btnApplyPwd.setToolTip(_translate("MainWindow", "Applies this password for all master cards")) + self.btnApplyPwd.setText(_translate("MainWindow", "Apply")) + self.Log.setTabText(self.Log.indexOf(self.tab_2), _translate("MainWindow", "Settings#1")) self.WorkTime.setItemText(0, _translate("MainWindow", "6 hour")) self.WorkTime.setItemText(1, _translate("MainWindow", "24 hour")) - self.WorkTime.setItemText(2, _translate("MainWindow", "all time")) - self.WorkTime.setItemText(3, _translate("MainWindow", "not work")) + self.WorkTime.setItemText(2, _translate("MainWindow", "not work")) + self.WorkTime.setItemText(3, _translate("MainWindow", "all time")) self.label.setText(_translate("MainWindow", "Work Time")) self.label_2.setText(_translate("MainWindow", "Start / Finish")) - self.StartFinish.setItemText(0, _translate("MainWindow", "on")) - self.StartFinish.setItemText(1, _translate("MainWindow", "off")) + self.StartFinish.setItemText(0, _translate("MainWindow", "off")) + self.StartFinish.setItemText(1, _translate("MainWindow", "on")) self.label_3.setText(_translate("MainWindow", "Check InitTime")) self.CheckInitTime.setItemText(0, _translate("MainWindow", "off")) self.CheckInitTime.setItemText(1, _translate("MainWindow", "on")) self.label_5.setText(_translate("MainWindow", "AutoDel Set")) self.AutoDel.setItemText(0, _translate("MainWindow", "off")) self.AutoDel.setItemText(1, _translate("MainWindow", "on")) - self.label_6.setText(_translate("MainWindow", "New Pass")) - self.label_7.setText(_translate("MainWindow", "Old Pass")) - self.PassCard.setText(_translate("MainWindow", "Pass Card")) + self.PassCard.setToolTip(_translate("MainWindow", "Creates the master card to write password and settings to a base station")) + self.PassCard.setText(_translate("MainWindow", " Create Pwd Card")) + self.SaveSet.setToolTip(_translate("MainWindow", "Stores settings to a file")) self.SaveSet.setText(_translate("MainWindow", "Save Set")) + self.LoadSet.setToolTip(_translate("MainWindow", "Loads settings from a file")) self.LoadSet.setText(_translate("MainWindow", "Load Set")) - self.Log.setTabText(self.Log.indexOf(self.tab_3), _translate("MainWindow", "Set")) + self.groupBox_7.setToolTip(_translate("MainWindow", "New password for a base station")) + self.groupBox_7.setTitle(_translate("MainWindow", "New Password")) + self.groupBox_8.setToolTip(_translate("MainWindow", "Old password of a base station")) + self.groupBox_8.setTitle(_translate("MainWindow", "Old Password")) + self.groupBox_9.setTitle(_translate("MainWindow", "Config by UART")) + self.cbUartPort.setCurrentText(_translate("MainWindow", "0")) + self.cbUartPort.setItemText(0, _translate("MainWindow", "0")) + self.cbUartPort.setItemText(1, _translate("MainWindow", "1")) + self.cbUartPort.setItemText(2, _translate("MainWindow", "2")) + self.cbUartPort.setItemText(3, _translate("MainWindow", "3")) + self.cbUartPort.setItemText(4, _translate("MainWindow", "4")) + self.cbUartPort.setItemText(5, _translate("MainWindow", "5")) + self.cbUartPort.setItemText(6, _translate("MainWindow", "6")) + self.cbUartPort.setItemText(7, _translate("MainWindow", "7")) + self.cbUartPort.setItemText(8, _translate("MainWindow", "8")) + self.cbUartPort.setItemText(9, _translate("MainWindow", "9")) + self.cbUartPort.setItemText(10, _translate("MainWindow", "10")) + self.cbUartPort.setItemText(11, _translate("MainWindow", "11")) + self.cbUartPort.setItemText(12, _translate("MainWindow", "12")) + self.cbUartPort.setItemText(13, _translate("MainWindow", "13")) + self.cbUartPort.setItemText(14, _translate("MainWindow", "14")) + self.cbUartPort.setItemText(15, _translate("MainWindow", "15")) + self.cbUartPort.setItemText(16, _translate("MainWindow", "16")) + self.cbUartPort.setItemText(17, _translate("MainWindow", "17")) + self.cbUartPort.setItemText(18, _translate("MainWindow", "18")) + self.cbUartPort.setItemText(19, _translate("MainWindow", "19")) + self.cbUartPort.setItemText(20, _translate("MainWindow", "20")) + self.cbUartPort.setItemText(21, _translate("MainWindow", "21")) + self.cbUartPort.setItemText(22, _translate("MainWindow", "22")) + self.cbUartPort.setItemText(23, _translate("MainWindow", "23")) + self.cbUartPort.setItemText(24, _translate("MainWindow", "24")) + self.cbUartPort.setItemText(25, _translate("MainWindow", "25")) + self.cbUartPort.setItemText(26, _translate("MainWindow", "26")) + self.cbUartPort.setItemText(27, _translate("MainWindow", "27")) + self.cbUartPort.setItemText(28, _translate("MainWindow", "28")) + self.cbUartPort.setItemText(29, _translate("MainWindow", "29")) + self.cbUartPort.setItemText(30, _translate("MainWindow", "30")) + self.cbUartPort.setItemText(31, _translate("MainWindow", "31")) + self.label_9.setText(_translate("MainWindow", "Com Port")) + self.label_10.setText(_translate("MainWindow", "Station Num")) + self.btnUartRead.setToolTip(_translate("MainWindow", "Reads settings of a base station by UART")) + self.btnUartRead.setText(_translate("MainWindow", "Read")) + self.btnUartWrite.setToolTip(_translate("MainWindow", "Writes settings to a base station by UART")) + self.btnUartWrite.setText(_translate("MainWindow", "Write")) + self.label_6.setText(_translate("MainWindow", "Fast Mark")) + self.cbFastMark.setItemText(0, _translate("MainWindow", "off")) + self.cbFastMark.setItemText(1, _translate("MainWindow", "on")) + self.cbAntennaGain.setItemText(0, _translate("MainWindow", "18 dB")) + self.cbAntennaGain.setItemText(1, _translate("MainWindow", "23 dB")) + self.cbAntennaGain.setItemText(2, _translate("MainWindow", "33 dB")) + self.cbAntennaGain.setItemText(3, _translate("MainWindow", "38 dB")) + self.cbAntennaGain.setItemText(4, _translate("MainWindow", "43 dB")) + self.cbAntennaGain.setItemText(5, _translate("MainWindow", "48 dB")) + self.label_7.setText(_translate("MainWindow", "Antenna Gain")) + self.Log.setTabText(self.Log.indexOf(self.tab_3), _translate("MainWindow", "Settings#2")) + self.btnClearText.setText(_translate("MainWindow", "Clear")) self.actionConnect.setText(_translate("MainWindow", "Connect")) self.actionChose_COM_port.setText(_translate("MainWindow", "Chose COM-port")) self.actionSave_log.setText(_translate("MainWindow", "Save log")) diff --git a/design.ui b/design.ui index 43d6bdf..21e3c2a 100644 --- a/design.ui +++ b/design.ui @@ -6,13 +6,16 @@ 0 0 - 408 - 453 + 530 + 703 SportiduinoPQ + + + @@ -21,11 +24,26 @@ + + + 0 + 0 + + + + + 75 + 16777215 + + 12 + + + Connect @@ -38,6 +56,9 @@ 12 + + + Com Port @@ -53,6 +74,9 @@ 12 + + + auto @@ -224,6 +248,24 @@ + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + 12 @@ -232,12 +274,15 @@ -3 + + + 0 - Read + Main @@ -270,10 +315,13 @@ 10 10 - 181 + 191 61 + + Reads a participant card + Read Card @@ -296,10 +344,16 @@ 10 140 - 141 - 41 + 111 + 31 + + + 0 + 0 + + @@ -307,9 +361,9 @@ - 0 + 10 80 - 211 + 191 20 @@ -320,9 +374,9 @@ - 0 + 10 240 - 211 + 191 20 @@ -330,39 +384,27 @@ Qt::Horizontal - - - - Card - 10 - 70 - 171 + 320 + 191 61 + + Inits a participant card + Init Card - - - - 10 - 10 - 171 - 51 - - - 10 - 140 + 390 151 31 @@ -371,209 +413,485 @@ AutoIncriment - - - - St - - + 10 - 110 - 91 - 31 + 270 + 191 + 41 - - Set Number - - + + + + Settings#1 + + 10 - 70 - 91 - 31 - - - - - - - 110 - 70 - 91 - 31 + 410 + 191 + 131 - - Set Start - - - - - - 110 - 110 - 91 - 31 - + + - - Set Finish + + Sleep Card + + + + 100 + 90 + 81 + 31 + + + + Creates the master card to force a base station to sleep and to wake-up at competion date + + + + + + Create + + + + + + 10 + 50 + 171 + 31 + + + + + + + + 2017 + 12 + 31 + + + + dd.MM.yyyy HH:mm + + + true + + + + + + 10 + 20 + 171 + 20 + + + + + + + Competion Date/Time + + - + 10 - 170 - 91 - 31 - - - - - 12 - - - - Clear St - - - - - - 110 - 170 - 91 - 31 + 540 + 191 + 71 - - - 12 - - - - Check St + + - - - - - 10 - 230 - 91 - 31 - - - + Dump Card + + + + 10 + 30 + 81 + 31 + + + + + 12 + + + + Reads the card contained punches log of a base station + + + + + + Read + + + + + + 100 + 30 + 81 + 31 + + + + Creates the master card to read punches log of a base station + + + + + + Create + + - + 10 - 10 - 91 - 31 - - - - Set Time - - - - - - 110 - 230 - 91 - 31 + 260 + 191 + 151 - - - 12 - + + - - Read Dump + + StationNum Card + + + + 100 + 30 + 81 + 31 + + + + Creates the master card to set number of a base station + + + + + + Set Num + + + + + + 10 + 70 + 81 + 31 + + + + Creates the master card to make a base station as a start station + + + + + + Set Start + + + + + + 100 + 70 + 81 + 31 + + + + Creates the master card to make a base station as a finish station + + + + + + Set Finish + + + + + + 100 + 110 + 81 + 31 + + + + + 12 + + + + Creates the master card to make a base station as a check station + + + + + + Check St + + + + + + 10 + 110 + 81 + 31 + + + + + 12 + + + + Creates the master card to make a base station as a clear station + + + + + + Clear St + + + + + + 10 + 30 + 81 + 31 + + + + true + + + Qt::AlignCenter + + + 1 + + + 255 + + - + 10 - 290 - 91 - 31 + 120 + 191 + 71 - - Sleep Card - - - - - - -3 - 30 - 211 - 41 - + + - - Qt::Horizontal + + Date/Time Card + + + + 100 + 30 + 81 + 31 + + + + Creates the master card to set clock of a base station + + + + + + Create + + - + - 0 - 140 - 211 - 31 + 10 + 190 + 191 + 71 - - Qt::Horizontal + + + + + Status Card + + + + 100 + 30 + 81 + 31 + + + + Creates the master card to get info about a base station + + + + + + Create + + + + + + 10 + 30 + 81 + 31 + + + + Reads the card contained info about a base station + + + + + + Read + + - + - -3 - 199 - 211 - 31 + 9 + 10 + 191 + 111 - - Qt::Horizontal + + Current password of a base station - - - - - -3 - 259 - 211 - 31 - + + - - Qt::Horizontal + + Password + + + + 100 + 70 + 81 + 31 + + + + Applies this password for all master cards + + + Apply + + + + + + 10 + 30 + 51 + 31 + + + + true + + + Qt::AlignCenter + + + 255 + + + + + + 70 + 30 + 51 + 31 + + + + true + + + Qt::AlignCenter + + + 255 + + + + + + 130 + 30 + 51 + 31 + + + + true + + + Qt::AlignCenter + + + 255 + + - Set + Settings#2 @@ -599,12 +917,12 @@ - all time + not work - not work + all time @@ -613,7 +931,7 @@ 10 10 - 91 + 111 31 @@ -648,12 +966,12 @@ - on + off - off + on @@ -662,8 +980,8 @@ 10 90 - 131 - 41 + 111 + 31 @@ -699,7 +1017,7 @@ 10 130 111 - 41 + 31 @@ -729,89 +1047,598 @@ - + 10 - 190 - 81 - 41 + 390 + 191 + 31 + + Creates the master card to write password and settings to a base station + - New Pass + Create Pwd Card - + - 10 - 230 - 81 - 41 + 110 + 430 + 91 + 31 + + Stores settings to a file + - Old Pass + Save Set - + - 100 - 190 - 101 + 10 + 430 + 91 31 + + Loads settings from a file + + + Load Set + - + - 100 - 230 - 101 - 31 + 10 + 240 + 191 + 71 + + New password for a base station + + + + + + New Password + + + + + 10 + 30 + 51 + 31 + + + + true + + + Qt::AlignCenter + + + 255 + + + + + + 70 + 30 + 51 + 31 + + + + true + + + Qt::AlignCenter + + + 255 + + + + + + 130 + 30 + 51 + 31 + + + + true + + + Qt::AlignCenter + + + 255 + + - + + + + 10 + 310 + 191 + 71 + + + + Old password of a base station + + + + + + Old Password + + + + + 10 + 30 + 51 + 31 + + + + true + + + Qt::AlignCenter + + + 255 + + + + + + 70 + 30 + 51 + 31 + + + + true + + + Qt::AlignCenter + + + 255 + + + + + + 130 + 30 + 51 + 31 + + + + true + + + Qt::AlignCenter + + + 255 + + + + 10 - 290 + 460 191 + 151 + + + + Config by UART + + + + + 120 + 30 + 61 + 31 + + + + + 12 + + + + + + + 0 + + + 0 + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + 18 + + + + + 19 + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + 24 + + + + + 25 + + + + + 26 + + + + + 27 + + + + + 28 + + + + + 29 + + + + + 30 + + + + + 31 + + + + + + + 10 + 30 + 81 + 31 + + + + + 12 + + + + + + + Com Port + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 10 + 70 + 101 + 31 + + + + + 12 + + + + + + + Station Num + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 10 + 110 + 81 + 31 + + + + Reads settings of a base station by UART + + + Read + + + + + + 100 + 110 + 81 + 31 + + + + Writes settings to a base station by UART + + + Write + + + + + + 120 + 70 + 61 + 31 + + + + true + + + Qt::AlignCenter + + + 1 + + + 255 + + + + + + + 10 + 170 + 111 31 - Pass Card + Fast Mark - + - 110 - 330 - 91 + 130 + 170 + 71 31 - - Save Set + + false + + + off + + + + + on + + - + + + + 130 + 210 + 71 + 31 + + + + false + + + 5 + + + + 18 dB + + + + + 23 dB + + + + + 33 dB + + + + + 38 dB + + + + + 43 dB + + + + + 48 dB + + + + 10 - 330 - 91 + 210 + 111 31 - Load Set + Antenna Gain @@ -820,11 +1647,33 @@ - - - Qt::ScrollBarAlwaysOff + + + QLayout::SetDefaultConstraint - + + + + + + + Qt::ScrollBarAlwaysOff + + + + + + + + 12 + + + + Clear + + + + @@ -853,11 +1702,7 @@ Connec choiseCom Log - cardLine - InitCard - AutoIncriment SetTime - StationLine SetNum SetStart SetFinish @@ -870,12 +1715,9 @@ StartFinish CheckInitTime AutoDel - NewPass - OldPass PassCard LoadSet SaveSet - textBrowser diff --git a/image/main1.JPG b/image/main1.JPG deleted file mode 100644 index 7a922bf..0000000 Binary files a/image/main1.JPG and /dev/null differ diff --git a/images/main1.JPG b/images/main1.JPG new file mode 100644 index 0000000..fd75489 Binary files /dev/null and b/images/main1.JPG differ diff --git a/sportiduino.py b/sportiduino.py index 4faaf9f..9a73550 100644 --- a/sportiduino.py +++ b/sportiduino.py @@ -27,6 +27,9 @@ import os import platform import re +from PyQt5.QtCore import QCoreApplication + +_translate = QCoreApplication.translate if PY3: def byte2int(x): @@ -48,6 +51,8 @@ class Sportiduino(object): START_STATION = 240 FINISH_STATION = 245 + CHECK_STATION = 248 + CLEAR_STATION = 249 # Protocol commands CMD_INIT_TIMECARD = b'\x41' @@ -62,6 +67,9 @@ class Sportiduino(object): CMD_READ_CARD = b'\x4b' CMD_READ_RAW = b'\x4c' CMD_INIT_SLEEPCARD = b'\x4e' + CMD_APPLY_PWD = b'\x4f' + CMD_INIT_INFOCARD = b'\x50' + CMD_READ_CARD_TYPE = b'\x51' CMD_BEEP_ERROR = b'\x58' CMD_BEEP_OK = b'\x59' @@ -71,6 +79,7 @@ class Sportiduino(object): RESP_CARD_RAW = b'\x65' RESP_VERS = b'\x66' RESP_MODE = b'\x69' + RESP_CARD_TYPE = b'\x70' RESP_ERROR = b'\x78' RESP_OK = b'\x79' @@ -79,22 +88,34 @@ class Sportiduino(object): ERR_WRITE_CARD = b'\x02' ERR_READ_CARD = b'\x03' ERR_READ_EEPROM = b'\x04' + ERR_CARD_NOT_FOUND = b'\x05' + + MASTER_CARD_GET_INFO = b'\xF9' + MASTER_CARD_SET_TIME = b'\xFA' + MASTER_CARD_SET_NUMBER = b'\xFB' + MASTER_CARD_SLEEP = b'\xFC' + MASTER_CARD_READ_DUMP = b'\xFD' + MASTER_CARD_SET_PASS = b'\xFE' + + MIN_CARD_NUM = 1 + MAX_CARD_NUM = 65000 class Version(object): - """Sportiduino firmware version.""" + """Sportiduino version.""" def __init__(self, value): """Initializes version by byte from master station. @param value: Byte from master station. """ self.value = value - self.major = value // 100 - self.minor = value % 100 + self.hw = (value >> 6) + 1 + self.major = ((value >> 2) & 0x0F) + 1 + self.minor = value & 0x03 def __str__(self): """Override __str__ method. @return: User friendly version string. """ - return 'v%d.%d.x' % (self.major, self.minor) + return 'v%d.%d.%d' % (self.hw, self.major, self.minor) def __init__(self, port=None, debug=False, logger=None): """Initializes communication with master station at port. @@ -138,7 +159,7 @@ def __init__(self, port=None, debug=False, logger=None): except SportiduinoException as msg: errors += 'port %s: %s\n' % (port, msg) - raise SportiduinoException('No Sportiduino master station found. Possible reasons: %s' % errors) + raise SportiduinoException(_translate("sportiduino","No Sportiduino master station found. Possible reasons: {}").format(errors)) def beep_ok(self): """One long beep and blink master station.""" @@ -167,9 +188,18 @@ def read_version(self): """ code, data = self._send_command(Sportiduino.CMD_READ_VERS) if code == Sportiduino.RESP_VERS: - return Sportiduino.Version(byte2int(data)) + self.version = byte2int(data[0]) + self.password = byte2int(data[1])<<16 | byte2int(data[2])<<8 | byte2int(data[3]) + self.settings = byte2int(data[4]) + self.antennaGain = byte2int(data[5]) + return Sportiduino.Version(byte2int(data[0])) return None + def read_card_type(self): + code, data = self._send_command(Sportiduino.CMD_READ_CARD_TYPE) + if code == Sportiduino.RESP_CARD_TYPE : + return data[0] + return 0xFF def read_card(self, timeout=None): """Reads out the card currently inserted into the station. @@ -180,7 +210,7 @@ def read_card(self, timeout=None): if code == Sportiduino.RESP_CARD_DATA: return self._parse_card_data(data) else: - raise SportiduinoException("Read card failed.") + raise SportiduinoException(_translate("sportiduino","Unknown error during card reading")) def poll_card(self): @@ -188,7 +218,7 @@ def poll_card(self): If card readed update self.card_data and return True. @return: Read card status.""" try: - self.card_data = self.read_card(timeout=0.5) + self.card_data = self.read_card() return True except SportiduinoTimeout: pass @@ -205,7 +235,7 @@ def read_card_raw(self): if code == Sportiduino.RESP_CARD_RAW: return self._parse_card_raw_data(data) else: - raise SportiduinoException("Read raw data failed.") + raise SportiduinoException("Read raw data failed") def read_backup(self): @@ -216,7 +246,7 @@ def read_backup(self): if code == Sportiduino.RESP_BACKUP: return self._parse_backup(data) else: - raise SportiduinoException("Read backup failed.") + raise SportiduinoException("Read backup failed") def init_card(self, card_number, page6=None, page7=None): @@ -237,25 +267,31 @@ def init_card(self, card_number, page6=None, page7=None): params += Sportiduino._to_str(t, 4) params += page6[:5] params += page7[:5] - self._send_command(Sportiduino.CMD_INIT_CARD, params, wait_response=False) + return self._send_command(Sportiduino.CMD_INIT_CARD, params, wait_response=True) def init_backupreader(self): """Initialize backupreader card.""" - self._send_command(Sportiduino.CMD_INIT_BACKUPREADER, wait_response=False) + self._send_command(Sportiduino.CMD_INIT_BACKUPREADER, wait_response=True) - def init_sleepcard(self): + def init_sleepcard(self, wakeup): """Initialize sleep card.""" - self._send_command(Sportiduino.CMD_INIT_SLEEPCARD, wait_response=False) - + params = b'' + params += int2byte(wakeup.date().year() - 2000) + params += int2byte(wakeup.date().month()) + params += int2byte(wakeup.date().day()) + params += int2byte(wakeup.time().hour()) + params += int2byte(wakeup.time().minute()) + params += int2byte(wakeup.time().second()) + self._send_command(Sportiduino.CMD_INIT_SLEEPCARD, params, wait_response=True) def init_cp_number_card(self, cp_number): """Initialize card for writing check point number to base station. @param cp_number: Check point number. """ params = int2byte(cp_number) - self._send_command(Sportiduino.CMD_INIT_CP_NUM_CARD, params, wait_response=False) + self._send_command(Sportiduino.CMD_INIT_CP_NUM_CARD, params, wait_response=True) def init_time_card(self, time=datetime.today()): @@ -269,10 +305,10 @@ def init_time_card(self, time=datetime.today()): params += int2byte(time.hour) params += int2byte(time.minute) params += int2byte(time.second) - self._send_command(Sportiduino.CMD_INIT_TIMECARD, params, wait_response=False) + self._send_command(Sportiduino.CMD_INIT_TIMECARD, params, wait_response=True) - def init_passwd_card(self, old_passwd=0, new_passwd=0, flags=0): + def init_passwd_card(self, old_passwd, new_passwd, settings, antennaGain): """Initialize card for writing new password to base station. @param old_passwd: Old password (default 0x000000). @param new_passwd: New password (default 0x000000). @@ -281,9 +317,51 @@ def init_passwd_card(self, old_passwd=0, new_passwd=0, flags=0): params = b'' params += Sportiduino._to_str(new_passwd, 3) params += Sportiduino._to_str(old_passwd, 3) - params += Sportiduino._to_str(flags, 1) - self._send_command(Sportiduino.CMD_INIT_PASSWDCARD, params, wait_response=False) + params += Sportiduino._to_str(settings, 1) + params += Sportiduino._to_str(antennaGain, 1) + self.password = new_passwd + self.settings = settings + self._send_command(Sportiduino.CMD_INIT_PASSWDCARD, params, wait_response=True) + + def init_info_card(self): + """Initialize card for writing check point number to base station. + @param cp_number: Check point number. + """ + params = b'' + self._send_command(Sportiduino.CMD_INIT_INFOCARD, params, wait_response=True) + + def read_info_card(self): + bs = BaseStation() + pageData = self.read_card_raw() + + if pageData[4][2] != 255 or pageData[4][1] != byte2int(Sportiduino.MASTER_CARD_GET_INFO): + raise SportiduinoException(_translate("sportiduino","The card contained info about a base station is not found")) + + bs.version = pageData[8][0] + bs.antennaGain = pageData[8][3] + bs.num = pageData[9][0] + bs.settings = pageData[9][1] + bs.batteryOk = pageData[9][2] + bs.mode = pageData[9][3] + bs.timestamp = pageData[10][0] << 24 + bs.timestamp |= pageData[10][1] << 16 + bs.timestamp |= pageData[10][2] << 8 + bs.timestamp |= pageData[10][3] + + bs.wakeup = pageData[11][0] << 24 + bs.wakeup |= pageData[11][1] << 16 + bs.wakeup |= pageData[11][2] << 8 + bs.wakeup |= pageData[11][3] + + return bs + def apply_pwd(self, pwd=0, flags=0): + + params = b'' + params += Sportiduino._to_str(pwd, 3) + params += Sportiduino._to_str(flags, 1) + self.password = pwd + self._send_command(Sportiduino.CMD_APPLY_PWD, params, wait_response=True) def write_pages6_7(self, page6, page7): """Write additional pages.""" @@ -301,7 +379,39 @@ def enable_continuous_read(self): def disable_continuous_read(self): """Disable continuous card read.""" self._set_mode(b'\x00') - + + @staticmethod + def card_name(card_type): + if(card_type == 0) : + return _translate("sportiduino","Unknown type") + elif(card_type == 1) : + return _translate("sportiduino","Compliant with ISO/IEC 14443-4") + elif(card_type == 2) : + return _translate("sportiduino","Compliant with ISO/IEC 18092 (NFC)") + elif(card_type == 3) : + return "MIFARE Classic Mini" + elif(card_type == 4) : + return "MIFARE Classic 1K" + elif(card_type == 5) : + return "MIFARE Classic 4K" + elif(card_type == 6) : + return "MIFARE Ultralight" + elif(card_type == 7) : + return "MIFARE Plus" + elif(card_type == 8) : + return "MIFARE DESFire" + elif(card_type == 9) : + return "TNP3XXX" + elif(card_type == 0xFF) : + return _translate("sportiduino","Not detected") + elif(card_type == 0x12) : + return "NTAG_213" + elif(card_type == 0x3E) : + return "NTAG_215" + elif(card_type == 0x6D) : + return "NTAG_216" + + return _translate("sportiduino","Unknown type") def _set_mode(self, mode): """Set master station read mode.""" @@ -315,19 +425,18 @@ def _connect_master_station(self, port): # Wait little time for it startup time.sleep(2) except (SerialException, OSError): - raise SportiduinoException("Could not open port '%s'" % port) + raise SportiduinoException(_translate("sportiduino","Could not open port {}").format(port)) try: self._serial.reset_input_buffer() except (SerialException, OSError): - raise SportiduinoException("Could not flush port '%s'" % port) + raise SportiduinoException(_translate("sportiduino","Could not flush port {}").format(port)) self.port = port self.baudrate = self._serial.baudrate - version = self.read_version() - if version is not None: - self._log_info("Master station %s on port '%s' connected" % (version, port)) - + 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)) def _send_command(self, code, parameters=None, wait_response=True, timeout=None): if parameters is None: @@ -362,7 +471,7 @@ def _read_response(self, timeout=None, wait_fragment=None): while True: byte = self._serial.read() if byte == b'': - raise SportiduinoTimeout('No response') + raise SportiduinoTimeout(_translate("sportiduino","No response")) elif byte == Sportiduino.START_BYTE: break @@ -390,10 +499,10 @@ def _read_response(self, timeout=None, wait_fragment=None): )) if not Sportiduino._cs_check(code + length_byte + data, checksum): - raise SportiduinoException('Checksum mismatch') + raise SportiduinoException(_translate("sportiduino","Checksum mismatch")) except (SerialException, OSError) as msg: - raise SportiduinoException('Error reading response: %s' % msg) + raise SportiduinoException(_translate("sportiduino","Error reading response: {}").format(msg)) if more_fragments: next_code, next_data = self._read_response(timeout, fragment_num + 1) @@ -435,21 +544,32 @@ def _to_str(i, len): @staticmethod - def _preprocess_response(code, data, log_debug): - if code == Sportiduino.RESP_ERROR: - if data == Sportiduino.ERR_COM: - raise SportiduinoException("COM error") - elif data == Sportiduino.ERR_WRITE_CARD: - raise SportiduinoException("Card write error") - elif data == Sportiduino.ERR_READ_CARD: - raise SportiduinoException("Card read error") - elif data == Sportiduino.ERR_READ_EEPROM: - raise SportiduinoException("EEPROM read error") + def _preprocess_response(func, data, log_debug): + err_code = int2byte(data[0]) + if func == Sportiduino.RESP_ERROR: + + card_type = data[1] + card = Sportiduino.card_name(data[1]) + + if err_code == Sportiduino.ERR_COM: + raise SportiduinoException(_translate("sportiduino","COM error")) + elif err_code == Sportiduino.ERR_WRITE_CARD: + raise SportiduinoException(_translate("sportiduino","Can't write the card ({})").format(card)) + elif err_code == Sportiduino.ERR_READ_CARD: + raise SportiduinoException(_translate("sportiduino","Can't read the card ({})").format(card)) + elif err_code == Sportiduino.ERR_READ_EEPROM: + raise SportiduinoException(_translate("sportiduino","Can't read EEPROM")) + elif err_code == Sportiduino.ERR_CARD_NOT_FOUND : + if card_type == 0xFF : + raise SportiduinoException(_translate("sportiduino","Card is not found")) + else : + raise SportiduinoException(_translate("sportiduino","Unsupported card type = {}").format(card_type)) else: - raise SportiduinoException("Error with code %s" % hex(byte2int(code))) - elif code == Sportiduino.RESP_OK: + raise SportiduinoException(_translate("sportiduino","Error code {}").format(hex(byte2int(err_code)))) + elif func == Sportiduino.RESP_OK: log_debug("Ok received") - return code, data + + return func, data @staticmethod @@ -473,6 +593,9 @@ def _cs_check(s, checksum): def _parse_card_data(data): # TODO check data length ret = {} + ret['master_card_flag'] = 0 + ret['master_card_type'] = 0 + ret['init_timestamp'] = 0 ret['card_number'] = Sportiduino._to_int(data[0:2]) ret['page6'] = data[2:6] ret['page7'] = data[6:10] @@ -488,6 +611,51 @@ def _parse_card_data(data): ret['punches'].append((cp, time)) return ret + + @staticmethod + def raw_data_to_card_data(data): + ret = {} + ret['master_card_flag'] = data[4][2] + ret['master_card_type'] = data[4][1] + ret['card_number'] = Sportiduino._to_int(data[4][0:2]) + ret['init_timestamp'] = Sportiduino._to_int(data[5][0:4]) + ret['page6'] = data[6][0:4] + ret['page7'] = data[7][0:4] + ret['punches'] = [] + + if ret['master_card_flag'] == 255: + return ret + + init_time_low = Sportiduino._to_int(data[5][1:4]) + init_time_high = data[5][0] + + for page in data: + if page < 8: + continue + + cp = data[page][0] + + if cp == 0 : + continue + + cp_timestamp = 0 + cp_time_low = Sportiduino._to_int(data[page][1:4]) + + if cp_time_low < init_time_low: + cp_timestamp = ((init_time_high + 1) << 24) | cp_time_low + else: + cp_timestamp = (init_time_high << 24) | cp_time_low + + time = datetime.fromtimestamp(cp_timestamp) + + if cp == Sportiduino.START_STATION: + ret['start'] = time + elif cp == Sportiduino.FINISH_STATION: + ret['finish'] = time + + ret['punches'].append((cp, time)) + + return ret @staticmethod @@ -504,16 +672,19 @@ def _parse_card_raw_data(data): def _parse_backup(data): ret = {} - cp = Sportiduino._to_int(data[0:2]) - ret['cp'] = cp + ret['cp'] = 0 ret['cards'] = [] - for i in range(2, len(data), 2): + + if len(data) < 1 : + return ret + + ret['cp'] = Sportiduino._to_int(data[0:1]) + + for i in range(1, len(data), 2): ret['cards'].append(Sportiduino._to_int(data[i:i + 2])) return ret - - class SportiduinoException(Exception): pass @@ -521,3 +692,233 @@ class SportiduinoException(Exception): class SportiduinoTimeout(SportiduinoException): pass +class BaseStation(object): + MODE_ACTIVE = 0 + MODE_WAIT = 1 + MODE_SLEEP = 2 + + START_STATION_NUM = 240 + FINISH_STATION_NUM = 245 + CHECK_STATION_NUM = 248 + CLEAR_STATION_NUM = 249 + + # UART + SERIAL_MSG_START1 = 0xFE + SERIAL_MSG_START2 = 0xEF + SERIAL_MSG_END1 = 0xFD + SERIAL_MSG_END2 = 0xDF + + SERIAL_FUNC_READ_INFO = 0xF0 + SERIAL_FUNC_WRITE_SETTINGS = 0xF1 + + SERIAL_RESP_STATUS = 0x1 + SERIAL_RESP_INFO = 0x2 + + SERIAL_OK = 0x0 + SERIAL_ERROR_CRC = 0x1 + SERIAL_ERROR_FUNC = 0x2 + SERIAL_ERROR_SIZE = 0x3 + SERIAL_ERROR_PWD = 0x4 + + def __init__(self): + self.version = 0 + self.mode = BaseStation.MODE_ACTIVE + self.settings = 0 + self.num = 0 + self.timestamp = 0 + self.wakeup = 0 + self.batteryOk = 0 + self.antennaGain = 7<<4 + + def hwVers(self): + return ((self.version >> 6) & 0x03) + 1 + + def fwMajorVers(self): + return ((self.version >> 2) & 0x0F) + 1 + + def fwMinorVers(self): + return self.version & 0x03 + + def readInfoBySerial(self, port, pwd1, pwd2, pwd3): + ser = Serial(port, baudrate=9600, timeout=10) + + msg = [] + + msg.append(BaseStation.SERIAL_FUNC_READ_INFO) + msg.append(pwd1) + msg.append(pwd2) + msg.append(pwd3) + + crc8 = 0 + + for x in msg: + crc8 ^= x + + msg.append(crc8) + + msg.insert(0,BaseStation.SERIAL_MSG_START2) + msg.insert(0,BaseStation.SERIAL_MSG_START1) + # Обязательно в начале сообщения дублируем первый байт + # Потому что после получения первого байта процессор только просыпается + # и UART не успевает синхронизироваться, поэтому первый байт не принимается + # и его нужно продублировать + msg.insert(0,BaseStation.SERIAL_MSG_START1) + msg.append(BaseStation.SERIAL_MSG_END1) + msg.append(BaseStation.SERIAL_MSG_END2) + + bmsg = bytes(msg) + + ser.write(bmsg) + msg = self._readResponse(ser) + ser.close() + + if len(msg) < 19: + raise SportiduinoException(_translate("sportiduino", "Invalid size of the response")) + + pos = 3; + self.version = msg[pos] + pos += 1 + + self.num = msg[pos] + pos += 1; + + self.settings = msg[pos] + pos += 1 + + self.batteryOk = msg[pos] + pos += 1 + + self.mode = msg[pos] + pos += 1 + + self.timestamp = msg[pos] << 24 + pos += 1 + self.timestamp |= msg[pos] << 16 + pos += 1 + self.timestamp |= msg[pos] << 8 + pos += 1 + self.timestamp |= msg[pos] + pos += 1 + + self.wakeup = msg[pos] << 24 + pos += 1 + self.wakeup |= msg[pos] << 16 + pos += 1 + self.wakeup |= msg[pos] << 8 + pos += 1 + self.wakeup |= msg[pos] + pos += 1 + + self.antennaGain = msg[pos] + + def writeSettingsBySerial(self, port, oldPwd1, oldPwd2, oldPwd3, newPwd1, newPwd2, newPwd3, num, settings, wakeup, gain): + ser = Serial(port, baudrate=9600, timeout=1) + + msg = [] + + msg.append(BaseStation.SERIAL_FUNC_WRITE_SETTINGS) + + # старый пароль + msg.append(oldPwd1) + msg.append(oldPwd2) + msg.append(oldPwd3) + # текущее время + utc = datetime.utcnow(); + msg.append(utc.year - 2000) + msg.append(utc.month) + msg.append(utc.day) + msg.append(utc.hour) + msg.append(utc.minute) + msg.append(utc.second) + # новый пароль + msg.append(newPwd1) + msg.append(newPwd2) + msg.append(newPwd3) + # номер станции + msg.append(num) + # настройки + msg.append(settings) + # время пробуждения + msg.append(wakeup.year - 2000) + msg.append(wakeup.month) + msg.append(wakeup.day) + msg.append(wakeup.hour) + msg.append(wakeup.minute) + msg.append(wakeup.second) + # усиление антенны + msg.append(gain) + + crc8 = self._serialCrc(msg, 0, len(msg)) + + msg.append(crc8) + + msg.insert(0,BaseStation.SERIAL_MSG_START2) + msg.insert(0,BaseStation.SERIAL_MSG_START1) + # Обязательно в начале сообщения дублируем первый байт + # Потому что после получения первого байта процессор только просыпается + # и UART не успевает синхронизироваться, поэтому первый байт не принимается + # и его нужно продублировать + msg.insert(0,BaseStation.SERIAL_MSG_START1) + msg.append(BaseStation.SERIAL_MSG_END1) + msg.append(BaseStation.SERIAL_MSG_END2) + + bmsg = bytes(msg) + + ser.write(bmsg) + + self._readResponse(ser) + + ser.close() + + def _serialCrc(self, data, start, end): + crc = 0 + + for i in range(start, end, 1): + crc ^= data[i] + + return crc + + def _readResponse(self, ser): + + ret = [] + + oldByte = 0 + curByte = 0 + + while True: + curByte = ser.read() + + if curByte == b'': + break; + + curByte = byte2int(curByte) + + ret.append(curByte) + + if oldByte == BaseStation.SERIAL_MSG_END1 and curByte == BaseStation.SERIAL_MSG_END2: + break; + + oldByte = curByte + + msgLen = len(ret) + + if msgLen < 5: + raise SportiduinoException(_translate("sportiduino", "No response from the base station")) + + crc = self._serialCrc(ret, 2, msgLen - 3) + + if ret[msgLen - 3] != crc: + raise SportiduinoException(_translate("sportiduino", "Checksum mismatch in the response")) + + if ret[2] == BaseStation.SERIAL_RESP_STATUS: + if ret[3] == BaseStation.SERIAL_ERROR_FUNC: + raise SportiduinoException(_translate("sportiduino", "Invalid function code")) + elif ret[3] == BaseStation.SERIAL_ERROR_CRC: + raise SportiduinoException(_translate("sportiduino", "Checksum mismatch in the request")) + elif ret[3] == BaseStation.SERIAL_ERROR_SIZE: + raise SportiduinoException(_translate("sportiduino", "Invalid size of the request")) + elif ret[3] == BaseStation.SERIAL_ERROR_PWD: + raise SportiduinoException(_translate("sportiduino", "Invalid password")) + + return ret + \ No newline at end of file diff --git a/translation/sportiduinopq.pro b/translation/sportiduinopq.pro new file mode 100644 index 0000000..2363ad5 --- /dev/null +++ b/translation/sportiduinopq.pro @@ -0,0 +1,7 @@ + SOURCES = ../sportiduino.py \ + ../sportiduinopq.py \ + ../design.py + +FORMS = ../design.ui + +TRANSLATIONS = sportiduinopq_ru.ts \ No newline at end of file diff --git a/translation/sportiduinopq_ru.qm b/translation/sportiduinopq_ru.qm new file mode 100644 index 0000000..0263ad8 Binary files /dev/null and b/translation/sportiduinopq_ru.qm differ diff --git a/translation/sportiduinopq_ru.ts b/translation/sportiduinopq_ru.ts new file mode 100644 index 0000000..46c8f4b --- /dev/null +++ b/translation/sportiduinopq_ru.ts @@ -0,0 +1,1153 @@ + + + + + MainWindow + + + SportiduinoPQ + + + + + Connect + Связь + + + + Com Port + COM порт + + + + auto + + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + 18 + + + + + 19 + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + 24 + + + + + 25 + + + + + 26 + + + + + 27 + + + + + 28 + + + + + 29 + + + + + 30 + + + + + 31 + + + + + Main + Основное + + + + Print + Печатать + + + + Select Printer + Выбрать + + + + Reads a participant card + Прочитать чип участника + + + + Read Card + Прочитать чип + + + + AutoPrint + Авто-печать + + + + Inits a participant card + Подготовить чип участника к старту + + + + Init Card + Подготовить чип + + + + AutoIncriment + Авто-увеличение + + + + Settings#1 + Настройки#1 + + + + Sleep Card + Мастер-чип "Сон" + + + + Creates a config card to force a base station to sleep and to wake-up at competion date + Создать мастер-чип для перевода базовой станции в режим сна + + + + Create + Создать + + + + dd.MM.yyyy HH:mm + + + + + Competion Date/Time + Начало соревнований + + + + Dump Card + Мастер-чип "Лог Отм." + + + + Reads a config card consists dump info + Прочитать чип содержащий журнал отметок базовой станции + + + + Read + Читать + + + + Creates a config card to read dump from a base station + Создать мастер-чип для получения журнала отметок базовой станции + + + + StationNum Card + Мастер-чип "Номер" + + + + Creates a config card to set a number for a base station + Создать мастер-чип для установки номера базовой станции + + + + Set Num + Создать + + + + Creates a config card to make a base station as a start station + Создать мастре-чип для установки базовой станции как станция "Старт" + + + + Set Start + Старт + + + + Creates a config card to make a base station as a finish station + Создать мастер-чип для установки базовой станции как станция "Финиш" + + + + Set Finish + Финиш + + + + Creates a config card to make a base station as a check station + Создать мастер-чип для установки базовой станции как станция "Проверка" + + + + Check St + Проверка + + + + Creates a config card to make a base station as a clear station + Создать мастер-чип для установки базовой станции как станция "Очистка" + + + + Clear St + Очистка + + + + Date/Time Card + Мастер-чип "Часы" + + + + Creates a config card to set date/time for a base station + Создать мастер-чип для установки часов базовой станции + + + + Creates the master card to read punches log of a base station + Создать мастер-чип для получения журнала отметок базовой станции + + + + Current password of a base station + Текущий пароль базовой станции + + + + Password + Пароль + + + + Applies current password for all next config cards + Применить текущий пароль для всех мастер-чипов + + + + Apply + OK + + + + Settings#2 + Настройки#2 + + + + 6 hour + 6 часов + + + + 24 hour + 24 часа + + + + not work + никогда + + + + all time + всегда + + + + Work Time + Актив. Время + + + + Start / Finish + Старт/Финиш + + + + off + нет + + + + on + да + + + + Check InitTime + Пров. Вр. Чипа + + + + AutoDel Set + Сброс Настр. + + + + Create Pwd Card + Создать чип настроек + + + + Stores settings to a file + Сохранить текущие настройки в файл + + + + Save Set + Сохр. наст. + + + + Loads settings from a file + Загрузить настройки из файла + + + + Load Set + Загр. наст. + + + + New password for a base station + Новый пароль для базовых станций + + + + New Password + Новый пароль + + + + Old password of a base station + Старый пароль базовых станций + + + + Old Password + Старый пароль + + + + Config by UART + Настройка по UART + + + + Station Num + Номер станции + + + + Reads settings of a base station by UART + Прочитать настройки базовой станции по UART + + + + Writes settings to a base station by UART + Записать настройки базовой станции по UART + + + + Write + Записать + + + + Fast Mark + Быст. Отметка + + + + 18 dB + + + + + 23 dB + + + + + 33 dB + + + + + 38 dB + + + + + 43 dB + + + + + 48 dB + + + + + Antenna Gain + Усил. Антенны + + + + Clear + Очистить + + + + Chose COM-port + Выбрать COM-порт + + + + Save log + Сохранить лог + + + + Open help.txt + Открыть help.txt + + + + Creates the master card to force a base station to sleep and to wake-up at competion date + Создать мастер-чип для перевода базовой станции в режим сна + + + + Reads the card contained punches log of a base station + Прочитать чип с журналом отметок базовой станции + + + + Creates the master card to set number of a base station + Создать мастер-чип для установки номера базовой станции + + + + Creates the master card to make a base station as a start station + Создать мастер-чип для установки базовой станции как станции "Старт" + + + + Creates the master card to make a base station as a finish station + Создать мастер-чип для установки базовой станции как станции "Финиш" + + + + Creates the master card to make a base station as a check station + Создать мастер-чип для установки базовой станции как станции "Проверка" + + + + Creates the master card to make a base station as a clear station + Создать мастер-чип для установки базовой станции как станции "Очистка" + + + + Creates the master card to set clock of a base station + Создать мастер-чип для установки часов базовой станции + + + + Status Card + Мастер-чип "Состояние" + + + + Creates the master card to get info about a base station + Создать мастер-чип для получения информации о состоянии базовой станции + + + + Reads the card contained info about a base station + Прочитать чип с информацией о состоянии базовой станции + + + + Applies this password for all master cards + Применить текущий пароль для всех мастер-чипов + + + + Creates the master card to write password and settings to a base station + Создать мастре-чип для записи пароля и настроек в базовую станцию + + + + sportiduino + + + Unknown type + Неизвестный тип + + + + Compliant with ISO/IEC 14443-4 + Совместимый с ISO/IEC 14443-4 + + + + Compliant with ISO/IEC 18092 (NFC) + Совместимый с ISO/IEC 18092 (NFC) + + + + Not detected + Не обнаружен + + + + COM error + Ошибка COM порта + + + + Can't write the card ({}) + Не могу записать чип ({}) + + + + Can't read the card ({}) + Не могу прочитать чип ({}) + + + + Can't read EEPROM + Не могу прочитать EEPROM + + + + Card is not found + Чип не обнаружен + + + + Unsupported card type = {} + Тип чипа = {} не поддерживается + + + + Error code {} + Код ошибки {} + + + + Ok received + Ответ Ok получен + + + + Could not open port {} + Не могу открыть порт {} + + + + Could not flush port {} + Не могу записать в порт {} + + + + Unknown error during card reading + Произошла неизвестная ошибка в процессе чтения чипа + + + + No response + Нет ответа от станции сопряжения + + + + Checksum mismatch + Контрольная сумма пакета данных не совпадает + + + + Error reading response: {} + Ошибка чтения ответа станции сопряжения {} + + + + No Sportiduino master station found. Possible reasons: {} + Станция сопряжения не обнаружена, возможные причины: {} + + + + The card contained info about a base station is not found + Чип с информацией о базовой станции не обнаружен + + + + The base station is not replied by UART. Perhaps the current password is invalid + Базовая станция не отвечает! Возможно установлен не верный пароль + + + + Invalid size of the response + Не верный размер ответа + + + + No response from the base station + Нет ответа от базовой станции + + + + Checksum mismatch in the response + Не совпадает контрольная сумма в ответе + + + + Invalid function code + Не верный код функции + + + + Checksum mismatch in the request + Не совпадает контрольная сумма в запросе + + + + Invalid size of the request + Не верный размер запроса + + + + Invalid password + Не верный пароль + + + + sportiduinopq + + + Master station {} on port {} is connected + Подключена станция сопряжения {} на порту {} + + + + Error: {} + Ошибка: {} + + + + Master station is disconnected + Станция сопряжения отключена + + + + Master station is not connected + Станция сопряжения не подключена + + + + The card ({}) has been initialized succefully + Чип участника ({}) успешно подготовлен к старту + + + + Error: not correct card number + Ошибка: недопустимый номер чипа + + + + The participant card N{} ({}) has been initialized succefully + Чип участника N{} ({}) успешно подготовлен к старту + + + + Card N{} + Чип N{} + + + + Start: {} + Старт: {} + + + + Punches (Check point - Time): + Отметки (КП - Время): + + + + Finish: {} + Финиш: {} + + + + No punches + Нет отметок + + + + Read a card + Начинаю читать чип + + + + Start to initialize a participant card + Начинаю подготовку чипа участника + + + + Card ({}) + Чип ({}) + + + + Master card to get info about a base station + Прочитан мастер-чип для получения информации о базовой станции + + + + Master card to set time of a base station + Прочитан мастер-чип для установки времени базовой станции + + + + Master card to set number of a base station + Прочитан мастер-чип для установки номера базовой станции + + + + Master card to sleep a base station + Прочитан мастер-чип для перевода базовой станции в режим сна + + + + Master card to get punches log of a base station + Прочитан мастер-чип для чтения лога базовой станции + + + + Master card to write password and settings to a base station + Прочитан мастер-чип для записи пароля и настроек базовой станции + + + + Uninitialized card + Чип не инициализирован + + + + Participant card N{} + Чип участника N{} + + + + Init time {} + Время инициализации {} + + + + Start + Старт + + + + Total punches {} + Всего отметок {} + + + + Finish + Финиш + + + + Start to connect a master station + Подключаю станцию сопряжения + + + + The participant card N{} ({}) has been initialized successfully + Чип участника N{} ({}) успешно подготовлен к старту + + + + Not correct card number + Недопустимый номер чипа + + + + Start to apply password + Устанавливаю текущий пароль + + + + Load settings from file /data/settings.json + Загружаю настройки из файла /data/settings.json + + + + Start to create a master card to get info about a base station + Начинаю подготовку мастер-чипа для чтения информации о базовой станции + + + + The master card has been created successfully + Мастер-чип успешно подготовлен + + + + Version: {}.{}.{} + Версия: {}.{}.{} + + + + Station N: {} + Станция N: {} + + + + (Start) + (Старт) + + + + (Finish) + (Финиш) + + + + (Check) + (Проверка) + + + + Settings: {} + Настройки: {} + + + + Battery: OK + Батарейки: в норме + + + + Battery: Low + Батарейки: низкий заряд, необходимо заменить + + + + Mode: Active + Режим: Активный + + + + Mode: Sleep + Режим: Сон + + + + Clock: {} + Часы: {} + + + + Alarm: {} + Будильник: {} + + + + Antenna Gain: {} + Усиление антенны: {} + + + + Settings displayed by UI has been chaged to the base station settings + Настройки в окне приложения изменены в соответствии с настройками базовой станции + + + + Start to read the info card + Читаю чип с информацией о базовой станции + + + + (Clear) + (Очистка) + + + + Mode: Wait + Режим: Ожидание + + + + Initialize the participant card + Начинаю подготовку чипа участника + + + + Write the master card to set number of a base station + Записывая мастер-чип для установки номера базовой станции + + + + Not correct station number + Недопустимый номер базовой станции + + + + Write the master card to set a base station as the start station + Записываю мастер-чип для установки базовой станции как стартовой станции + + + + Write the master card to set a base station as the finish station + Записываю мастер-чип для установки базовой станции как финишной станции + + + + Write the master card to set a base station as the check station + Записываю мастер-чип для установки базовой станции как станции проверки + + + + Write the master card to set a base station as the clear station + Записываю мастер-чип для установки базовой станции как станции очистки + + + + Write the master card to get log of a base station + Записываю мастер-чип для получения журнала отметок на базовой станции + + + + Read the card contained log of a base station + Читаю чип с журналом отметок на базовой станции + + + + No log data available + Чип с логом базовой станции не обнаружен + + + + Write the master card to sleep a base station + Записываю мастер-чип для перевода базовой станции в режим сна + + + + Apply the current password + Устанавливаю текущий пароль + + + + The password has been applied successfully + Текущий пароль успешно установлен + + + + Write the master card to get info about a base station + Записываю мастер-чип для получения информации о состоянии базовой станции + + + + Read the card contained info about a base station + Читаю мастер-чип с информацией о состоянии базовой станции + + + + Reads info about a base station by UART + Читаю информацию о состоянии базовой станции по UART + + + + Writes settings ans password to a base station by UART + Записываю новый пароль и настройки в базовую станцию по UART + + + + The master card has been written successfully + Мастер-чип успешно записан + + + + Write the master card to set clock of a base station. Put the card on a base station after second signal + Записываю мастер-чип для установки часов базовой станции. Приложите данный чип к базовой станции после второго сигнала + + + + Write the master card to write new password and settings to a base station + Записываю мастер-чип для установки нового пароля и настроек базовой станции + + + + Settings has been loaded successfully + Настройки успешно загружены + + + + Click 'Apply Pwd' on #Settings1 tab + Нажмите на "Применить" пароль в закладке Настройки#1 + + + + Save settings to file /data/settings.json + Сохраняю настройки в файл /data/settings.json + + + + Settings has been saved successfully + Настройки успешно сохранены + + + + Settings and password has been written successfully + Настройки и пароль были успешно записаны + + + + Cards: + Чипы: + + +