444 lines
18 KiB
Python
444 lines
18 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
将极电子程序 .ats 文件转换为 ACP 项目 .ACP 文件
|
||
- 设备 FullName 映射
|
||
- 方法名映射
|
||
- 参数格式转换(.ats → .ACP)
|
||
- IOBoardGroup 只保留台架序号参数
|
||
"""
|
||
|
||
import json
|
||
import glob
|
||
import os
|
||
import uuid
|
||
import copy
|
||
|
||
# ============================================================
|
||
# 1. 设备 FullName 映射
|
||
# ============================================================
|
||
DEVICE_MAPPING = {
|
||
# 相同设备(无需改 FullName)
|
||
"TSMasterCAN.CAN": "TSMasterCAN.CAN",
|
||
"Command.Delay": "Command.Delay",
|
||
"Command.CommandMath": "Command.CommandMath",
|
||
"DeviceCommand.Device.PW8001": "DeviceCommand.Device.PW8001",
|
||
|
||
# 需要映射的设备
|
||
"DeviceCommand.Device.IOBoardCard": "DeviceCommand.Device.IOBoardGroup",
|
||
"DeviceCommand.Device.IT6724C": "DeviceCommand.Devices.IT6720",
|
||
"DeviceCommand.Device.SQ0090G1D1": "DeviceCommand.Devices.Chroma61800", # 三相交流源 → Chroma61800
|
||
"DeviceCommand.Device.PSB11500_60": "DeviceCommand.Devices.S7200", # 交流源/负载 → S7200 直流源载一体机
|
||
"DeviceCommand.Device.MSO44B": "DeviceCommand.Devices.TektronixMSO",
|
||
"DeviceCommand.Device.EA3040_40C": "DeviceCommand.Devices.ANEVH80", # 水冷机/负载 → ANEVH80
|
||
"DeviceCommand.Device.Chroma_63206A": "DeviceCommand.Devices.ANEVH80", # 电子负载 → ANEVH80
|
||
|
||
# 暂无对应设备,保持原 FullName(方法名使用占位符)
|
||
"DeviceCommand.Device.WS_68070": "DeviceCommand.Device.WS_68070",
|
||
"DeviceCommand.Device.AFV33030": "DeviceCommand.Device.AFV33030",
|
||
"DeviceCommand.Device.DAQ970A": "DeviceCommand.Device.DAQ970A",
|
||
"DeviceCommand.Device.XcpDevice": "DeviceCommand.Device.XcpDevice",
|
||
"ATS.Commands.CurveMonitorCommands": "ATS.Commands.CurveMonitorCommands",
|
||
}
|
||
|
||
# ============================================================
|
||
# 2. 方法名映射 {(旧FullName): {旧方法名: 新方法名}}
|
||
# ============================================================
|
||
|
||
# --- IOBoardCard → IOBoardGroup ---
|
||
IOBOARD_METHOD_MAP = {
|
||
"WriteMultiIO": "批量写输出开关",
|
||
"WriteSingleIO": "写输出开关",
|
||
}
|
||
|
||
# --- IT6724C → IT6720 ---
|
||
IT6720_METHOD_MAP = {
|
||
"RemoteMode": "切换远程控制模式",
|
||
"DCOutput_OFF": "设置输出开关", # 参数值 false
|
||
"OFF": "设置输出开关", # 参数值 false
|
||
"ON": "设置输出开关", # 参数值 true
|
||
"SetVoltage": "设置输出电压",
|
||
"SetCurrent": "设置输出电流",
|
||
}
|
||
|
||
# --- PSB11500_60 → S7200 (直流源载一体机) ---
|
||
S7200_METHOD_MAP = {
|
||
"Set_RemoteMode": "设置为远程模式",
|
||
"Set_SourceMode_SetVoltage": "设置电压",
|
||
"Set_SourceMode_SetCurrent": "设置CC模式电流",
|
||
"Set_SourceMode_SetPower": "设置正向功率阈值",
|
||
"Set_SinkMode_SetVoltage": "设置电压",
|
||
"Set_SinkMode_SetCurrent": "设置CC模式电流",
|
||
"Set_SinkMode_SetPower": "设置反向功率阈值",
|
||
"Set_DC_Input": "设置电压",
|
||
"Set_DC_Output": "设置电压",
|
||
"LoadOn": "设置通道开关", # 开启负载
|
||
"LoadOff": "设置通道开关", # 关闭负载
|
||
"Get_ActualVoltage": "查询实时电压",
|
||
"Get_ActualCurrent": "查询实时电流",
|
||
"Get_ActualPower": "查询功率",
|
||
"MeasureVoltage": "查询实时电压",
|
||
"MeasureCurrent": "查询实时电流",
|
||
"MeasurePower": "查询功率",
|
||
}
|
||
|
||
# --- SQ0090G1D1 → Chroma61800 (交流源) ---
|
||
CHROMA61800_METHOD_MAP = {
|
||
"RemoteMode": "设置输出开关Async", # true=远程
|
||
"ON": "设置输出开关Async", # true=开启
|
||
"OFF": "设置输出开关Async", # false=关闭
|
||
"SetVoltage": "设置交流电压Async",
|
||
"SetFrequency": "设置频率Async",
|
||
"SetOutputMode": "设置单三相模式Async",
|
||
"SetPhaseAngle": "设置开机角度Async",
|
||
"SetIndividualVoltage": "设置交流电压Async",
|
||
"MeasureVoltage": "读取交流电压Async",
|
||
"MeasureCurrent": "读取交流电流Async",
|
||
}
|
||
|
||
# --- EA3040_40C → ANEVH80 ---
|
||
ANEVH80_METHOD_MAP = {
|
||
"Set_RemoteMode": "占位符",
|
||
"Set_Voltage": "占位符",
|
||
"Set_Current": "占位符",
|
||
"DCOutput_ON": "占位符",
|
||
"DCOutput_OFF": "占位符",
|
||
}
|
||
|
||
# --- Chroma_63206A → ANEVH80 ---
|
||
CHROMA63206A_METHOD_MAP = {
|
||
"SetModeCC": "占位符",
|
||
"SetModeCV": "占位符",
|
||
"SetModeCR": "占位符",
|
||
"ON": "占位符",
|
||
"OFF": "占位符",
|
||
"SetVoltageL1": "占位符",
|
||
"SetVoltageL2": "占位符",
|
||
"SetCurrentL1": "占位符",
|
||
"SetCurrentL2": "占位符",
|
||
"SetResistanceL1": "占位符",
|
||
"SetResistanceL2": "占位符",
|
||
"SetCurrentSlewRatePositive": "占位符",
|
||
"SetCurrentSlewRateNegative": "占位符",
|
||
"MeasureVoltage": "占位符",
|
||
"MeasureCurrent": "占位符",
|
||
"MeasurePower": "占位符",
|
||
}
|
||
|
||
# --- MSO44B → TektronixMSO ---
|
||
TEKTRONIX_METHOD_MAP = {
|
||
"Acquire_Run": "设置采集状态",
|
||
"Acquire_Stop": "设置采集状态",
|
||
"ClearStatus": "清除状态",
|
||
"Reset": "清除状态",
|
||
"Set_AcquireMode": "设置采集模式",
|
||
"Set_ChannelState": "设置通道显示开关",
|
||
"Set_ChannelScale": "设置通道垂直刻度",
|
||
"Set_ChannelUnit": "设置通道垂直刻度",
|
||
"Set_ChannelCoupling": "设置通道垂直刻度",
|
||
"Set_ChannelProbe": "设置通道垂直刻度",
|
||
"Set_ChannelBandwidth": "设置通道垂直刻度",
|
||
"Set_HorizontalScale": "设置水平刻度",
|
||
"Set_RecordLength": "设置记录长度",
|
||
"Set_StopAfter": "设置采集状态",
|
||
"Set_TriggerMode": "设置采集模式",
|
||
"Set_TriggerType_Edge": "设置采集模式",
|
||
"Set_TriggerEdgeSource": "设置测量源",
|
||
"Set_TriggerEdgeSlope": "设置测量类型",
|
||
"Set_TriggerLevel": "设置通道垂直位置",
|
||
"Set_WaveformSource": "设置测量源",
|
||
"Setup_Measurement": "开启测量项",
|
||
"Get_MeasurementValue": "查询测量项当前值",
|
||
"Save_Screenshot": "保存屏幕截图",
|
||
"Save_Waveform": "保存屏幕截图",
|
||
}
|
||
|
||
# --- PW8001 → PW8001 (同设备,方法名需适配) ---
|
||
PW8001_METHOD_MAP = {
|
||
"Set_TestMode_WIDE": "设置测试模式_WIDE",
|
||
"Set_TestMode_IEC": "设置测试模式_IEC",
|
||
"QueryVoltageWithRatio": "查询电压_含变比",
|
||
"QueryCurrentWithRatio": "查询电流_含变比",
|
||
"QueryPowerWithoutRatio": "查询功率_不含变比",
|
||
"QueryTotalPowerP123": "查询总功率P123",
|
||
"QueryVoltageTHD": "查询电压THD",
|
||
"QueryCurrentTHD": "查询电流THD",
|
||
}
|
||
|
||
# --- WS_68070 (占位符) ---
|
||
WS68070_METHOD_MAP = {
|
||
"Get_ThreePhase_Frequency": "占位符_GetFrequency",
|
||
"Get_ThreePhase_MaxCurrent": "占位符_GetMaxCurrent",
|
||
"Get_ThreePhase_MaxVoltage": "占位符_GetMaxVoltage",
|
||
"Get_ThreePhase_SumActivePower": "占位符_GetSumActivePower",
|
||
"Set_ATE_Load_A_Current": "占位符_SetLoadCurrent",
|
||
"Set_ATE_Load_CurrentMode": "占位符_SetLoadMode",
|
||
"Set_ATE_Load_Load": "占位符_SetLoad",
|
||
"Set_ATE_Load_PowerMode": "占位符_SetPowerMode",
|
||
"Set_ATE_Load_Uninstall": "占位符_SetUninstall",
|
||
"Set_ThreePhase_SumActivePower": "占位符_SetSumActivePower",
|
||
}
|
||
|
||
# --- AFV33030 (占位符) ---
|
||
AFV33030_METHOD_MAP = {
|
||
"Set_General_OutputVoltage": "占位符_SetOutputVoltage",
|
||
"Set_ThreePhase_OutputVoltage": "占位符_SetThreePhaseVoltage",
|
||
}
|
||
|
||
# --- DAQ970A (占位符) ---
|
||
DAQ970A_METHOD_MAP = {
|
||
"Set_DCDefaultCurrent": "占位符_SetCurrent",
|
||
"Set_DCDefaultVoltage": "占位符_SetVoltage",
|
||
}
|
||
|
||
# --- XcpDevice (占位符) ---
|
||
XCP_METHOD_MAP = {
|
||
"Connect": "占位符_Connect",
|
||
"Disconnect": "占位符_Disconnect",
|
||
"ReadMemory": "占位符_ReadMemory",
|
||
"WriteMemory": "占位符_WriteMemory",
|
||
}
|
||
|
||
# --- CurveMonitorCommands (占位符) ---
|
||
CURVE_MONITOR_METHOD_MAP = {
|
||
"CAN曲线记录_启动": "占位符_StartCANRecord",
|
||
"CAN曲线记录_停止": "占位符_StopCANRecord",
|
||
"设备参数记录_启动": "占位符_StartDeviceRecord",
|
||
"设备参数记录_停止": "占位符_StopDeviceRecord",
|
||
}
|
||
|
||
# 汇总所有方法映射
|
||
METHOD_MAPPING = {
|
||
"DeviceCommand.Device.IOBoardCard": IOBOARD_METHOD_MAP,
|
||
"DeviceCommand.Device.IT6724C": IT6720_METHOD_MAP,
|
||
"DeviceCommand.Device.PSB11500_60": S7200_METHOD_MAP,
|
||
"DeviceCommand.Device.SQ0090G1D1": CHROMA61800_METHOD_MAP,
|
||
"DeviceCommand.Device.EA3040_40C": ANEVH80_METHOD_MAP,
|
||
"DeviceCommand.Device.Chroma_63206A": CHROMA63206A_METHOD_MAP,
|
||
"DeviceCommand.Device.MSO44B": TEKTRONIX_METHOD_MAP,
|
||
"DeviceCommand.Device.PW8001": PW8001_METHOD_MAP,
|
||
"DeviceCommand.Device.WS_68070": WS68070_METHOD_MAP,
|
||
"DeviceCommand.Device.AFV33030": AFV33030_METHOD_MAP,
|
||
"DeviceCommand.Device.DAQ970A": DAQ970A_METHOD_MAP,
|
||
"DeviceCommand.Device.XcpDevice": XCP_METHOD_MAP,
|
||
"ATS.Commands.CurveMonitorCommands": CURVE_MONITOR_METHOD_MAP,
|
||
}
|
||
|
||
# ============================================================
|
||
# 3. 格式转换函数
|
||
# ============================================================
|
||
|
||
def convert_param_ats_to_acp(param):
|
||
"""将 .ats 参数格式转换为 .ACP 参数格式"""
|
||
new_param = {}
|
||
new_param["ID"] = param.get("ID", str(uuid.uuid4()))
|
||
new_param["IsVisible"] = param.get("IsVisible", True)
|
||
new_param["IsEditable"] = True # .ACP 新增字段
|
||
new_param["Name"] = param.get("Name", "")
|
||
new_param["Type"] = param.get("Type", "")
|
||
new_param["Category"] = param.get("Category", 0)
|
||
new_param["Value"] = param.get("Value", None)
|
||
new_param["LowerLimit"] = param.get("LowerLimit", None)
|
||
new_param["UpperLimit"] = param.get("UpperLimit", None)
|
||
new_param["Result"] = param.get("Result", True)
|
||
new_param["IsUseVar"] = param.get("IsUseVar", False)
|
||
new_param["VariableName"] = param.get("VariableName", None)
|
||
new_param["VariableID"] = param.get("VariableID", None)
|
||
# 不包含: IsGlobal, InitialValue, IsSave, IsOutputToReport
|
||
return new_param
|
||
|
||
|
||
def convert_ioboard_params(params, old_method_name):
|
||
"""IOBoardGroup 参数处理:
|
||
根据 IOBoardGroup 的方法签名重新生成参数
|
||
写输出开关(台架序号, 站号, 开始地址, data)
|
||
批量写输出开关(台架序号, 站号, 开始地址, datas)
|
||
只保留台架序号参数(使用公共变量),其他参数先不写
|
||
"""
|
||
int_type = "System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"
|
||
byte_type = "System.Byte, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"
|
||
ushort_type = "System.UInt16, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"
|
||
bool_type = "System.Boolean, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"
|
||
bool_arr_type = "System.Boolean[], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"
|
||
ct_type = "System.Threading.CancellationToken, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"
|
||
|
||
# 台架序号参数(使用公共变量,Value=null,IsUseVar=true)
|
||
station_param = {
|
||
"ID": str(uuid.uuid4()),
|
||
"IsVisible": True,
|
||
"IsEditable": True,
|
||
"Name": "台架序号",
|
||
"Type": int_type,
|
||
"Category": 0,
|
||
"Value": None,
|
||
"LowerLimit": None,
|
||
"UpperLimit": None,
|
||
"Result": True,
|
||
"IsUseVar": True,
|
||
"VariableName": "台架序号",
|
||
"VariableID": None
|
||
}
|
||
|
||
new_params = [station_param]
|
||
|
||
# 根据方法类型添加对应的参数(值设为 null,用户后续填写)
|
||
if "批量" in old_method_name or "Multi" in old_method_name:
|
||
# 批量写输出开关: 台架序号, 站号, 开始地址, datas
|
||
new_params.append(make_param("站号", byte_type, None))
|
||
new_params.append(make_param("开始地址", ushort_type, None))
|
||
new_params.append(make_param("datas", bool_arr_type, None))
|
||
else:
|
||
# 写输出开关: 台架序号, 站号, 开始地址, data
|
||
new_params.append(make_param("站号", byte_type, None))
|
||
new_params.append(make_param("开始地址", ushort_type, None))
|
||
new_params.append(make_param("data", bool_type, None))
|
||
|
||
return new_params
|
||
|
||
|
||
def make_param(name, type_str, value):
|
||
"""创建一个 ACP 格式的参数"""
|
||
return {
|
||
"ID": str(uuid.uuid4()),
|
||
"IsVisible": True,
|
||
"IsEditable": True,
|
||
"Name": name,
|
||
"Type": type_str,
|
||
"Category": 0,
|
||
"Value": value,
|
||
"LowerLimit": None,
|
||
"UpperLimit": None,
|
||
"Result": True,
|
||
"IsUseVar": False,
|
||
"VariableName": None,
|
||
"VariableID": None
|
||
}
|
||
|
||
|
||
def convert_method(method, old_full_name):
|
||
"""转换 Method 对象"""
|
||
if not method:
|
||
return None
|
||
|
||
new_method = {}
|
||
old_name = method.get("Name", "")
|
||
|
||
# 映射 FullName
|
||
new_full_name = DEVICE_MAPPING.get(old_full_name, old_full_name)
|
||
new_method["Name"] = old_name
|
||
new_method["FullName"] = new_full_name
|
||
|
||
# 映射方法名
|
||
method_map = METHOD_MAPPING.get(old_full_name, {})
|
||
if old_name in method_map:
|
||
new_method["Name"] = method_map[old_name]
|
||
|
||
# 转换参数(不包含 DeviceID)
|
||
old_params = method.get("Parameters", [])
|
||
if old_full_name == "DeviceCommand.Device.IOBoardCard":
|
||
new_method["Parameters"] = convert_ioboard_params(old_params, old_name)
|
||
else:
|
||
new_method["Parameters"] = [convert_param_ats_to_acp(p) for p in old_params]
|
||
|
||
return new_method
|
||
|
||
|
||
def convert_step(step):
|
||
"""转换单个 Step"""
|
||
new_step = {}
|
||
new_step["ID"] = step.get("ID", str(uuid.uuid4()))
|
||
new_step["IsUsed"] = step.get("IsUsed", True)
|
||
new_step["Index"] = step.get("Index", 0)
|
||
new_step["Name"] = step.get("Name", "")
|
||
new_step["StepType"] = step.get("StepType", "方法")
|
||
|
||
# 转换 Method
|
||
old_method = step.get("Method")
|
||
if old_method:
|
||
old_full_name = old_method.get("FullName", "")
|
||
new_step["Method"] = convert_method(old_method, old_full_name)
|
||
else:
|
||
new_step["Method"] = None
|
||
|
||
# 转换 SubProgram(嵌套的子程序)
|
||
sub_program = step.get("SubProgram")
|
||
if sub_program and isinstance(sub_program, dict):
|
||
new_step["SubProgram"] = convert_program(sub_program)
|
||
else:
|
||
new_step["SubProgram"] = None
|
||
|
||
# 循环相关
|
||
new_step["LoopCount"] = step.get("LoopCount", None)
|
||
new_step["LoopStartStepId"] = step.get("LoopStartStepId", None)
|
||
|
||
# 跳转相关
|
||
new_step["OKExpression"] = step.get("OKExpression", None)
|
||
new_step["GotoSettingString"] = step.get("GotoSettingString", "")
|
||
new_step["OKGotoStepID"] = step.get("OKGotoStepID", None)
|
||
new_step["NGGotoStepID"] = step.get("NGGotoStepID", None)
|
||
new_step["Description"] = step.get("Description", None)
|
||
|
||
return new_step
|
||
|
||
|
||
def convert_program(program):
|
||
"""转换整个 ProgramVM 结构"""
|
||
new_program = {}
|
||
new_program["ID"] = program.get("ID", str(uuid.uuid4()))
|
||
|
||
# 转换 StepCollection
|
||
old_steps = program.get("StepCollection", [])
|
||
new_program["StepCollection"] = [convert_step(s) for s in old_steps]
|
||
|
||
# ErrorStepCollection
|
||
new_program["ErrorStepCollection"] = []
|
||
|
||
# 转换 Parameters(顶层参数)
|
||
old_params = program.get("Parameters", [])
|
||
new_program["Parameters"] = [convert_param_ats_to_acp(p) for p in old_params]
|
||
|
||
return new_program
|
||
|
||
|
||
def convert_file(input_path, output_path):
|
||
"""转换单个文件"""
|
||
with open(input_path, encoding='utf-8-sig') as f:
|
||
data = json.load(f)
|
||
|
||
result = convert_program(data)
|
||
|
||
with open(output_path, 'w', encoding='utf-8') as f:
|
||
json.dump(result, f, ensure_ascii=False, indent=2)
|
||
|
||
|
||
# ============================================================
|
||
# 4. 主程序
|
||
# ============================================================
|
||
|
||
if __name__ == "__main__":
|
||
input_dir = r"C:\Users\kk\Desktop\ACP\极电子程序"
|
||
output_dir = r"D:\ACP\测试项\ACP输出"
|
||
|
||
os.makedirs(output_dir, exist_ok=True)
|
||
|
||
files = glob.glob(os.path.join(input_dir, "*.ats"))
|
||
print(f"找到 {len(files)} 个 .ats 文件")
|
||
|
||
success = 0
|
||
failed = 0
|
||
|
||
for f in files:
|
||
basename = os.path.splitext(os.path.basename(f))[0]
|
||
output_path = os.path.join(output_dir, f"{basename}.ACP")
|
||
|
||
try:
|
||
convert_file(f, output_path)
|
||
print(f" ✓ {basename}.ats → {basename}.ACP")
|
||
success += 1
|
||
except Exception as e:
|
||
print(f" ✗ {basename}.ats 失败: {e}")
|
||
failed += 1
|
||
|
||
print(f"\n转换完成: 成功 {success}, 失败 {failed}")
|
||
print(f"输出目录: {output_dir}")
|