#!/opt/homebrew/bin/python3 # -*- coding:utf-8 -*- from PyQt6.QtCore import QThread, pyqtSignal, QMutex from logs import log import json from influxDB import influxdb from ser import myserial from environment import env import matplotlib from matplotlib import pyplot import numpy from globals import _G class Command(QThread): logMsg = pyqtSignal(str) runOver = pyqtSignal() mutex = QMutex() def __init__(self, port=myserial, name='', cmdValue='', payload='', rspLen=0, timeout=1000, extAtt = ''): super().__init__() self.port = port self.cmdInfo = {} self.setCmdData(name, cmdValue, payload, rspLen, timeout, extAtt) self.namespace = {} self.namespace['tsdb'] = influxdb self.namespace['matplotlib'] = matplotlib self.namespace['plot'] = pyplot self.namespace['numpy'] = numpy self.updateNamespace() def setCmdData(self, name = '', cmdValue = '', payload = '', rspLen = 0, timeout = 1000, extAtt = ''): if isinstance(cmdValue, str): try: self.cmdInfo['cmdValue'] = bytearray().fromhex(cmdValue) except: self.cmdInfo['cmdValue'] = bytearray() log.error('illeagle cmd str') else: self.cmdInfo['cmdValue'] = cmdValue if isinstance(payload, str): try: self.cmdInfo['payload'] = bytearray().fromhex(payload) except: self.cmdInfo['payload'] = bytearray() log.error('illeagle cmd data str') else: self.cmdInfo['payload'] = payload self.cmdInfo['name'] = name self.cmdInfo['rspLen'] = rspLen self.cmdInfo['timeout'] = timeout self.cmdInfo['extAtt'] = {} if extAtt: try: self.cmdInfo['extAtt'] = json.loads(extAtt) except: self.cmdInfo['extAtt'] = {} def updateNamespace(self): self.namespace['cmdInfo'] = self.cmdInfo self.namespace['env'] = env.toDict() def setScript(self, script): self.script = script def setSendingCheckScript(self, script): self.sendingCheckScript = script def setRecvingCheckScript(self, script): self.recvingCheckScript = script def setSendingCodecScript(self, script): self.sendingCodecScript = script def setRecvingCodecScript(self, script): self.recvingCodecScript = script def __scriptSendingCheck(self, data): if not hasattr(self, 'sendingCheckScript'): return data if not isinstance(self.sendingCheckScript, str): return data if len(self.sendingCheckScript) == 0: return data namespace = {} exec(self.sendingCheckScript, namespace) try: ret = namespace['check_value'](data) if ret: chsm = bytearray((int(ret)).to_bytes(2, byteorder='big')) log.debug('sendingCheckScript ret :', ret, ' ', chsm.hex(' ')) return data + chsm except: log.error('failed to exec function -> sendingCheckScript') self.logMsg.emit('指令' + self.cmdInfo['name'] + '发送校验脚本执行出错') return data def __scriptRecvingCheck(self, data): if not hasattr(self, 'recvingCheckScript'): return True if not isinstance(self.recvingCheckScript, str): return True if len(self.recvingCheckScript) == 0: return True namespace = {} exec(self.recvingCheckScript, namespace) try: ret = namespace['check'](data) log.debug('recv check: ', ret) return ret except: log.error('failed to exec function -> recvingCheckScript') self.logMsg.emit('指令' + self.cmdInfo['name'] + '接收校验脚本执行出错') return False def __scriptSendingCodec(self, data): if not hasattr(self, 'sendingCodecScript'): return data if not isinstance(self.sendingCodecScript, str): return data if len(self.sendingCodecScript) == 0: return data namespace = {} exec(self.sendingCodecScript, namespace) try: ret = namespace['encode'](data) if ret: log.debug('sendingCodecScript ret :', ret.hex(' ')) return ret except: log.error('failed to exec function -> sendingCheckScript') self.logMsg.emit('指令' + self.cmdInfo['name'] + '发送编码脚本执行出错') return data def __scriptEncodeLen(self, dataLen): if not hasattr(self, 'sendingCodecScript'): return dataLen if not isinstance(self.sendingCodecScript, str): return dataLen if len(self.sendingCodecScript) == 0: return dataLen namespace = {} exec(self.sendingCodecScript, namespace) try: ret = namespace['encodeLen'](dataLen) if ret: return ret except: log.error('failed to exec function -> encodeLen') self.logMsg.emit('指令' + self.cmdInfo['name'] + '计算编码长度失败') return dataLen def __scriptRecvingCodec(self, data): if not hasattr(self, 'recvingCodecScript'): return data if not isinstance(self.recvingCodecScript, str): return data if len(self.recvingCodecScript) == 0: return data namespace = {} exec(self.recvingCodecScript, namespace) try: ret = namespace['decode'](data) if ret: log.debug('recvingCodecScript ret :', ret.hex(' ')) return ret except: log.error('failed to exec function -> recvingCodecScript') self.logMsg.emit('指令' + self.cmdInfo['name'] + '接收解码脚本执行出错') return data #发送数据校验之前回调函数 def __scriptTxCbBeforeChecking(self, txData): if self.namespace['txCbBeforeChecking'] == None: return txData try: self.updateNamespace() ok, ret, msg = self.namespace['txCbBeforeChecking'](txData) log.debug('txCbBeforeChecking ret :', ret.hex(' ')) if ok: txData = ret if isinstance(msg, str) and len(msg) > 0: self.logMsg.emit(msg) except: log.error('failed to exec function -> txCbBeforeChecking') self.logMsg.emit('指令' + self.cmdInfo['name'] + '发送数据校验之前回调函数执行失败') return txData #发送数据编码之前回调函数 def __scriptTxCbBeforeCodingAfterChecking(self, txData): if self.namespace['txCbBeforeCodingAfterChecking'] == None: return txData try: self.updateNamespace() ok, ret, msg = self.namespace['txCbBeforeCodingAfterChecking'](txData) log.debug('txCbBeforeCodingAfterChecking ret :', ret.hex(' ')) if ok: txData = ret if isinstance(msg, str) and len(msg) > 0: self.logMsg.emit(msg) except: log.error('failed to exec function -> txCbBeforeCodingAfterChecking') self.logMsg.emit('指令' + self.cmdInfo['name'] + '发送数据编码之前回调函数执行失败') return txData #发送数据之前回调函数 def __scriptTxCbBeforeSendingAfterCoding(self, txData): if self.namespace['txCbBeforeSendingAfterCoding'] == None: return txData try: self.updateNamespace() ok, ret, msg = self.namespace['txCbBeforeSendingAfterCoding'](txData) log.debug('txCbBeforeSendingAfterCoding ret :', ret.hex(' ')) if ok: txData = ret if isinstance(msg, str) and len(msg) > 0: self.logMsg.emit(msg) except: log.error('failed to exec function -> txCbBeforeSendingAfterCoding') self.logMsg.emit('指令' + self.cmdInfo['name'] + '发送数据之前回调函数执行失败') return txData #收到指令数据后解码之前回调函数 def __scriptRxCbAfterReceivingBeforeDecoding(self, rxData): if self.namespace['rxCbAfterReceivingBeforeDecoding'] == None: return rxData try: self.updateNamespace() ok, ret, msg = self.namespace['rxCbAfterReceivingBeforeDecoding'](rxData) log.debug('rxCbAfterReceivingBeforeDecoding ret :', ret.hex(' ')) if ok: if isinstance(msg, str) and len(msg) > 0: self.logMsg.emit(msg) return ret except: log.error('failed to exec function -> rxCbAfterReceivingBeforeDecoding') self.logMsg.emit('指令' + self.cmdInfo['name'] + '收到指令数据后解码之前回调函数执行失败') return rxData #指令数据解码之后校验之前回调函数 def __scriptRxCbAfterDecoingBeforeChecking(self, rxData): if self.namespace['rxCbAfterDecoingBeforeChecking'] == None: return rxData try: self.updateNamespace() ok, ret, msg = self.namespace['rxCbAfterDecoingBeforeChecking'](rxData) log.debug('rxCbAfterDecoingBeforeChecking ret :', ret.hex(' ')) if ok: if isinstance(msg, str) and len(msg) > 0: self.logMsg.emit(msg) return ret except: log.error('failed to exec function -> rxCbAfterDecoingBeforeChecking') self.logMsg.emit('指令' + self.cmdInfo['name'] + '指令数据解码之后校验之前回调函数执行失败') return rxData #指令数据校验之后回调函数 def __scriptRxCbAfterChecking(self, rxData): if self.namespace['rxCbAfterChecking'] == None: return rxData try: self.updateNamespace() ok, ret, msg = self.namespace['rxCbAfterChecking'](rxData) log.debug('rxCbAfterChecking ret :', ret.hex(' ')) if ok: if isinstance(msg, str) and len(msg) > 0: self.logMsg.emit(msg) return ret except: log.error('failed to exec function -> rxCbAfterChecking') self.logMsg.emit('指令' + self.cmdInfo['name'] + '指令数据校验之后回调函数执行失败') return rxData def run(self): try: Command.mutex.lock() self.namespace['_G'] = _G #第一次赋值,此处不可去掉 self.namespace['txCbBeforeChecking'] = None self.namespace['txCbBeforeCodingAfterChecking'] = None self.namespace['txCbBeforeSendingAfterCoding'] = None self.namespace['rxCbAfterReceivingBeforeDecoding'] = None self.namespace['rxCbAfterDecoingBeforeChecking'] = None self.namespace['rxCbAfterChecking'] = None exec(self.script, self.namespace) ba = bytearray(b'') if (len(bytearray(self.cmdInfo['cmdValue'])) != 0): ba = ba + bytearray(self.cmdInfo['cmdValue']) if (len(bytearray(self.cmdInfo['payload'])) != 0): ba = ba + bytearray(self.cmdInfo['payload']) if len(ba) == 0: log.warning('no cmd data to send, return') return txBa = self.__scriptTxCbBeforeChecking(ba) txBa = self.__scriptSendingCheck(txBa) txBa = self.__scriptTxCbBeforeCodingAfterChecking(txBa) txBa = self.__scriptSendingCodec(txBa) txBa = self.__scriptTxCbBeforeSendingAfterCoding(txBa) self.cmdInfo['txPacket'] = txBa ok, rxBa = self.port.sendCmd( txBa, self.__scriptEncodeLen(self.cmdInfo['rspLen']), self.cmdInfo['timeout'] ) self.cmdInfo['rxPacket'] = rxBa rxBa = self.__scriptRxCbAfterReceivingBeforeDecoding(rxBa) if len(rxBa) != 0: rxBa = self.__scriptRecvingCodec(rxBa) self.cmdInfo['rxPacketDecoded'] = rxBa rxBa = self.__scriptRxCbAfterDecoingBeforeChecking(rxBa) if len(rxBa) == 0: self.cmdInfo['rxPacketCheckOk'] = None else: self.cmdInfo['rxPacketCheckOk'] = self.__scriptRecvingCheck(rxBa) rxBa = self.__scriptRxCbAfterChecking(rxBa) log.debug('cmd exec over:', self.cmdInfo['name'], ' ', ok) if ok == -1: self.logMsg.emit('指令无应答或者应答长度不足') self.runOver.emit() except Exception as e: log.error(e) self.logMsg.emit(f'脚本错误: {e}') finally: Command.mutex.unlock()