381 lines
13 KiB
Python
381 lines
13 KiB
Python
|
|
#!/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()
|