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)}")