TG-PlatformPlus/UserScripts/sapcs.py

725 lines
26 KiB
Python
Raw Normal View History

2026-03-02 14:29:58 +08:00
import os, time, csv, struct, sys
import numpy as np
sys.path.append(r'.\UserScripts')
from user_common import wordData2HexStr, nowStr, nowStr1, checkValue, params_to_int
from CRC import crc16 as checkValue
SENDHEADER = ''
RSPHEADER = ''
RETRYTIMES = 3
CYCLES = 1
TIMEOUT = 0.2
DEBUG = True
# 启动函数,命令开始会调用此函数
def start():
global recvData, deviceData
try:
log_i(f"[{devInfo['name']}] {cmdInfo['name']}".center(80, '-'))
deviceData = _G.get(f"{devInfo['name']}")
if not deviceData:
deviceData = {}
if 'data' not in deviceData:
deviceData['data'] = {}
if 'info' not in deviceData:
deviceData['info'] = {}
if 'status' not in deviceData:
deviceData['status'] = {}
if 'config' not in deviceData:
deviceData['config'] = {}
if 'channelsInfoTable' not in deviceData:
channelsInfoTable = {
'channel1':{
'name':'channel1',
'powerStatus':{
'value':0,
'address':0x0054,
'mask':0x0001,
'len':1
},
'signalVoltage':{
'value':1,
'address':0x0020,
'len':2
},
'powerCurrent':{
'value':1,
'address':0x0030,
'len':2
},
'powerVoltage':{
'value':1,
'address':0x0032,
'len':2
},
'signalVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0060,
'len':1
},
'b':{
'value':0,
'address':0x0068,
'len':1
},
'unit':'uV'
},
'powerCurrentCalibParams':{
'scale':{
'value':1,
'address':0x0070,
'len':1
},
'b':{
'value':0,
'address':0x0080,
'len':1
},
'unit':'uA'
},
'powerVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0071,
'len':1
},
'b':{
'value':0,
'address':0x0081,
'len':1
},
'unit':'mV',
}
},
'channel2':{
'name':'channel2',
'powerStatus':{
'value':0,
'address':0x0054,
'mask':0x0002,
'len':1
},
'signalVoltage':{
'value':1,
'address':0x0022,
'len':2
},
'powerCurrent':{
'value':1,
'address':0x0034,
'len':2
},
'powerVoltage':{
'value':1,
'address':0x0036,
'len':2
},
'signalVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0061,
'len':1
},
'b':{
'value':0,
'address':0x0069,
'len':1
},
'unit':'uV'
},
'powerCurrentCalibParams':{
'scale':{
'value':1,
'address':0x0072,
'len':1
},
'b':{
'value':0,
'address':0x0082,
'len':1
},
'unit':'uA'
},
'powerVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0073,
'len':1
},
'b':{
'value':0,
'address':0x0083,
'len':1
},
'unit':'mV',
}
},
'channel3':{
'name':'channel3',
'powerStatus':{
'value':0,
'address':0x0054,
'mask':0x0004,
'len':1
},
'signalVoltage':{
'value':1,
'address':0x0024,
'len':2
},
'powerCurrent':{
'value':1,
'address':0x0038,
'len':2
},
'powerVoltage':{
'value':1,
'address':0x003A,
'len':2
},
'signalVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0062,
'len':1
},
'b':{
'value':0,
'address':0x006A,
'len':1
},
'unit':'uV'
},
'powerCurrentCalibParams':{
'scale':{
'value':1,
'address':0x0074,
'len':1
},
'b':{
'value':0,
'address':0x0084,
'len':1
},
'unit':'uA'
},
'powerVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0075,
'len':1
},
'b':{
'value':0,
'address':0x0085,
'len':1
},
'unit':'mV',
}
},
'channel4':{
'name':'channel4',
'powerStatus':{
'value':0,
'address':0x0054,
'mask':0x0008,
'len':1
},
'signalVoltage':{
'value':1,
'address':0x0026,
'len':2
},
'powerCurrent':{
'value':1,
'address':0x003C,
'len':2
},
'powerVoltage':{
'value':1,
'address':0x003E,
'len':2
},
'signalVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0063,
'len':1
},
'b':{
'value':0,
'address':0x006B,
'len':1
},
'unit':'uV'
},
'powerCurrentCalibParams':{
'scale':{
'value':1,
'address':0x0076,
'len':1
},
'b':{
'value':0,
'address':0x0086,
'len':1
},
'unit':'uA'
},
'powerVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0077,
'len':1
},
'b':{
'value':0,
'address':0x0087,
'len':1
},
'unit':'mV',
}
},
'channel5':{
'name':'channel5',
'powerStatus':{
'value':0,
'address':0x0054,
'mask':0x0010,
'len':1
},
'signalVoltage':{
'value':1,
'address':0x0028,
'len':2
},
'powerCurrent':{
'value':1,
'address':0x0040,
'len':2
},
'powerVoltage':{
'value':1,
'address':0x0042,
'len':2
},
'signalVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0064,
'len':1
},
'b':{
'value':0,
'address':0x006C,
'len':1
},
'unit':'uV'
},
'powerCurrentCalibParams':{
'scale':{
'value':1,
'address':0x0078,
'len':1
},
'b':{
'value':0,
'address':0x0088,
'len':1
},
'unit':'uA'
},
'powerVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0079,
'len':1
},
'b':{
'value':0,
'address':0x0089,
'len':1
},
'unit':'mV',
}
},
'channel6':{
'name':'channel6',
'powerStatus':{
'value':0,
'address':0x0054,
'mask':0x0020,
'len':1
},
'signalVoltage':{
'value':1,
'address':0x002A,
'len':2
},
'powerCurrent':{
'value':1,
'address':0x0044,
'len':2
},
'powerVoltage':{
'value':1,
'address':0x0046,
'len':2
},
'signalVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0065,
'len':1
},
'b':{
'value':0,
'address':0x006D,
'len':1
},
'unit':'uV'
},
'powerCurrentCalibParams':{
'scale':{
'value':1,
'address':0x007A,
'len':1
},
'b':{
'value':0,
'address':0x008A,
'len':1
},
'unit':'uA'
},
'powerVoltageCalibParams':{
'scale':{
'value':1,
'address':0x007B,
'len':1
},
'b':{
'value':0,
'address':0x008B,
'len':1
},
'unit':'mV',
}
},
'channel7':{
'name':'channel7',
'powerStatus':{
'value':0,
'address':0x0054,
'mask':0x0040,
'len':1
},
'signalVoltage':{
'value':1,
'address':0x002C,
'len':2
},
'powerCurrent':{
'value':1,
'address':0x0048,
'len':2
},
'powerVoltage':{
'value':1,
'address':0x004A,
'len':2
},
'signalVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0066,
'len':1
},
'b':{
'value':0,
'address':0x006E,
'len':1
},
'unit':'uV'
},
'powerCurrentCalibParams':{
'scale':{
'value':1,
'address':0x007C,
'len':1
},
'b':{
'value':0,
'address':0x008C,
'len':1
},
'unit':'uA'
},
'powerVoltageCalibParams':{
'scale':{
'value':1,
'address':0x007D,
'len':1
},
'b':{
'value':0,
'address':0x008D,
'len':1
},
'unit':'mV',
}
},
'channel8':{
'name':'channel8',
'powerStatus':{
'value':0,
'address':0x0054,
'mask':0x0080,
'len':1
},
'signalVoltage':{
'value':1,
'address':0x002E,
'len':2
},
'powerCurrent':{
'value':1,
'address':0x004C,
'len':2
},
'powerVoltage':{
'value':1,
'address':0x004E,
'len':2
},
'signalVoltageCalibParams':{
'scale':{
'value':1,
'address':0x0067,
'len':1
},
'b':{
'value':0,
'address':0x006F,
'len':1
},
'unit':'uV'
},
'powerCurrentCalibParams':{
'scale':{
'value':1,
'address':0x007E,
'len':1
},
'b':{
'value':0,
'address':0x008E,
'len':1
},
'unit':'uA'
},
'powerVoltageCalibParams':{
'scale':{
'value':1,
'address':0x007F,
'len':1
},
'b':{
'value':0,
'address':0x008F,
'len':1
},
'unit':'mV',
}
}
}
deviceData['channelsInfoTable'] = channelsInfoTable
else:
channelsInfoTable = deviceData['channelsInfoTable']
deviceData['status']['StopAll'] = False
_G.set(devInfo['name'], deviceData)
except Exception as e:
log_e(f"Error in start. {str(e)}")
finish()
# 此函数会被重复调用间隔10毫秒直到finish()
def loop():
global recvData, deviceData
try:
read_device_info()
finish()
except Exception as e:
log_e(f"Error in loop. {str(e)}")
finish()
# 接收数据处理函数,当收到数据会调用此函数
def recvDataHandler(data):
global recvData
try:
recvData = recvData + data
except Exception as e:
log_e(f"Error in recvDataHandler. {str(e)}")
finish()
def log_du(str):
try:
deviceData = _G.get(f"{devInfo['name']}")
if (deviceData and 'config' in deviceData and 'flagDebug' in deviceData['config']):
debug = deviceData['config']['flagDebug']
else:
debug = False
if debug or DEBUG:
log_d(str)
except Exception as e:
raise Exception(f"Error in log_du(): {str(e)}")
def set_flagDebug(flag):
try:
deviceData = _G.get(f"{devInfo['name']}")
if not deviceData:
deviceData = {}
if 'config' not in deviceData:
deviceData['config'] = {}
deviceData['config']['flagDebug'] = flag
_G.set(devInfo['name'], deviceData)
return True
except Exception as e:
log_e(f"Error in set_flagDebug(): {str(e)}")
return False
def exeCmd(cmd):
try:
global recvData
data = bytearray().fromhex(cmd[0])
data += bytearray(checkValue(data).to_bytes(2, 'little'))
for i in range(RETRYTIMES):
log_du(f"[{nowStr()}] Sent:{wordData2HexStr(data)}")
recvData = bytearray()
send(data)
time.sleep(TIMEOUT)
rspLen = int(cmd[1])
if len(recvData) >= rspLen:
log_du(f"[{nowStr()}] Echo:{wordData2HexStr(recvData[0:rspLen])}")
crc = int.from_bytes(recvData[rspLen-2:rspLen], byteorder='little')
calc_value = checkValue(recvData[0:rspLen-2])
# log(f"{crc:04X}, {calc_value:04X}")
if crc == calc_value:
return [True, recvData[0:rspLen]]
return [False, None]
except Exception as e:
raise Exception(f"Error in exeCmd({cmd}): {str(e)}")
def read_registers(startAddress, count):
try:
ret = exeCmd([f"0103 {startAddress:04X} {count:04X}", count*2+6])
if ret[0]:
registers = {}
# log(str(ret[1]))
for i in range(count):
registers[f"0x{startAddress+i:04X}"] = ret[1][4+2*i]*256 + ret[1][4+2*i+1]
return [0, registers]
else:
return [-1, None]
except Exception as e:
raise Exception(f"Error in read_registers(): {str(e)}")
def update_dict_from_registers(dictData, registers):
try:
if not dictData or not registers:
return False
# log(str(dictData))
# log(str(registers))
for key, value in dictData.items():
# log(f"{str(key)}, {str(value)}")
if isinstance(value, dict):
if 'address' in value:
if f"0x{value['address']:04X}" in registers:
value['value'] = 0
for i in range(value['len']):
value['value'] = (value['value']<<16) + registers[f"0x{value['address']+i:04X}"]
# log(f"0x{value['address']+i:04X}")
# log(str(registers[f"0x{value['address']+i:04X}"]))
if 'mask' in value:
value['value'] = value['value'] & value['mask']
# if key == 'powerStatus':
# log(f"{value['value']}, {value['mask']}, {i}")
else:
update_dict_from_registers(value, registers)
else:
pass
# log(str(dictData))
return True
except Exception as e:
raise Exception(f"Error in update_dict_from_registers(): {str(e)}")
def read_device_info():
try:
deviceData = _G.get(f"{devInfo['name']}")
if not deviceData or 'channelsInfoTable' not in deviceData:
return False
else:
channelsInfoTable = deviceData['channelsInfoTable']
registers = {}
#读取0x0020~0x004F寄存器并存为字典
registers1 = read_registers(0x0020, 0x0030)
registers2 = read_registers(0x0054, 0x0001)
#读取0x0060~0x008F寄存器并存为字典
registers3 = read_registers(0x0060, 0x0020)
if registers1[0] == 0 and registers2[0] == 0 and registers3[0] == 0:
registers = {**registers1[1], **registers2[1], **registers3[1]}
log(str(registers))
#从寄存器数据字典中提取数据存储至channelsInfoTable中
update_dict_from_registers(channelsInfoTable, registers)
deviceData['channelsInfoTable'] = channelsInfoTable
_G.set(devInfo['name'], deviceData)
log(str(deviceData))
#显示channelsInfoTable中的数据
except Exception as e:
log_e(f"Error in read_device_info(): {str(e)}")
return False
def write_registers_from_dict(dictData, registers):
try:
if not dictData or not registers:
return False
# log(str(dictData))
# log(str(registers))
for key, value in dictData.items():
# log(f"{str(key)}, {str(value)}")
if isinstance(value, dict):
if 'address' in value:
if f"0x{value['address']:04X}" in registers:
if 'mask' in value: #执行指令读取当前配置根据mask, 将要写入的位与当前配置做运算,再执行写配置指令
if value['len'] >= 1:
ret = exeCmd([f"0103 {value['address']:04X} {value['len']:04X}", 6+value['len']*2])
if ret[0]:
data = 0
for i in range(value['len']):
data = data<<16 + int(ret[1][4+2*i:6+2*i],16)
ret = exeCmd([f"0110 {value['address']:04X} {value['len']:04X} {data|value['mask']:0{value['len']*4}X}", 6+value['len']*2])
if not ret[0]:
raise Exception(f"fail to write registers({value['address']:04X}, {value['len']}).")
else:
raise Exception(f"fail to read registers({value['address']:04X}, {value['len']}).")
else:
raise Exception(f"len={str(value['len'])} is error. ")
else: #执行写入指令
if value['len'] >= 1:
ret = exeCmd([f"0110 {value['address']:04X} {value['len']:04X} {value['value']:0{value['len']*4}X}", 6+value['len']*2])
if not ret[0]:
raise Exception(f"fail to write registers({value['address']:04X}, {value['len']}).")
else:
raise Exception(f"len={str(value['len'])} is error. ")
else:
write_registers_from_dict(value, registers)
else:
pass
# log(str(dictData))
return True
except Exception as e:
raise Exception(f"Error in write_registers_from_dict(): {str(e)}")