package faultRecordProtocol import ( "fmt" "strconv" "strings" ) // FunctionCodeNames 命令控制符(功能码),FaultFilter 文档 5.4.1 var FunctionCodeNames = map[int]string{ 1: "清除设备故障波形", 2: "采样通道配置", 3: "手动触发故障录波", 4: "设备对时", 5: "故障录波采样频率", 6: "配置可配采样通道", 7: "故障录波功能状态控制", } // DangerousFunctionCodes 设置前需要醒目确认的功能码 var DangerousFunctionCodes = map[int]string{ 1: "清除设备上的故障波形,不可恢复", 3: "立即触发一次故障录波", 4: "修改设备时间", } // 设备种类(界面与平台使用;协议 type 见 DeviceKindProtocolType) const ( DeviceKindAGate = "aGate" // aGate/MCA,平台设备类型 1 DeviceKindAPowerPE = "aPowerPE" // aPower-PE,平台设备类型 0 DeviceKindAPowerMPPT = "aPowerMPPT" // aPower-MPPT,平台设备类型 2,SN 与 aPower 相同 DeviceKindAHub = "aHub" // aHub(即 aPbox2.0),平台设备类型 3 ) // DeviceKindProtocolType 设备种类对应 377 报文中的 type(用户确认,2026-10-20);空字符串表示暂不支持 var DeviceKindProtocolType = map[string]string{ DeviceKindAGate: DeviceTypeAGate, DeviceKindAPowerPE: DeviceTypePE, DeviceKindAPowerMPPT: DeviceTypeMPPT, DeviceKindAHub: DeviceTypeAPbox, } // PeHwVerNames aPower PE 硬件版本 → 版本名称(内部名称) var PeHwVerNames = map[int]string{ 0: "aPower 1.0", 2: "aPower 1.2(澳洲)/aPower 1.3(北美)", 4: "aPower 1.4", 20: "aPower 2/aPower 2(LR)", 21: "aPower S", 22: "aPower 2(SH)", 23: "aPower 2.1", 24: "aPower 2.1S", } // mpptPeHwVers 支持 aPower-MPPT 的 PE 硬件版本(目前只有 aPower S、aPower 2.1S,后续可能扩展) var mpptPeHwVers = map[int]bool{21: true, 24: true} // SupportsMPPT 该 PE 硬件版本的 aPower 是否带 MPPT func SupportsMPPT(peHwVer int) bool { return mpptPeHwVers[peHwVer] } // RealtimeCodeNames 实时数据类别,FaultFilter 文档 5.1 var RealtimeCodeNames = map[int]string{ 1: "故障总体信息", 2: "设备故障录波功能基本信息", 3: "故障录波总目录", } // TriggerSourceNames 事件触发源(F15),FaultFilter 文档 10.4 var TriggerSourceNames = map[uint16]string{ 0x0FF0: "手动触发 _Fix", 0x0FF1: "模拟故障触发 _Auto", 0x1000: "SL_DSP 预留触发源 16_1", 0x1001: "并网发生状态切换故障", 0x1002: "离网发生 aPower 离运问题", 0x1003: "油机发生状态切换故障", 0x5000: "PE_INV 预留触发源 16_1", 0x5001: "运行态下逆变故障", 0xD000: "MPPT 预留触发源 16_1", 0xD001: "运行态下 MPPT 故障", 0xD800: "APBOX2.0 预留触发源 16_1", 0xD801: "运行态下 APBOX2.0 故障", 0xE000: "DIF 预留触发源 16_1", 0xE001: "并网发生状态切换故障", 0xE002: "离网发生 aPower 离运问题", } // internalErrorCodes 设备内部通信错误判定码(F13),FaultFilter 文档 10.5 var internalErrorCodes = map[uint64]string{ 0x3: "下发命令与子设备回复的命令不一致", 0x4: "数据读取阶段:子设备回复错误", 0x5: "数据读取阶段:回复的数据类别不符", 0x6: "记录传输阶段:起始报文接收错误", 0x7: "记录传输阶段:后续数据未接收完成", 0x8: "记录传输阶段:数据块不连续", 0x9: "记录传输阶段:数据块内序号不连续", 0xa: "记录传输阶段:收到多余的后续数据", 0xb: "记录传输阶段:首包数据过短", 0xc: "记录传输结束阶段:后续数据未接收完成", 0xd: "数据读取阶段:接收超时", 0xe: "记录传输阶段:接收超时", 0xf: "记录传输结束阶段:接收超时", 0x10: "其他命令:接收超时", 0x11: "记录传输阶段:后续数据接收超时", 0x12: "参数读写阶段:读/写类型不一致", 0x13: "参数读写阶段:回复的功能码不一致", 0x14: "参数读写阶段:回复数据过短", 0x15: "参数读写阶段:接收超时", 0x16: "参数读写阶段:后续数据未接收完成", } // subDeviceErrorCodes 子设备错误码(F12),FaultFilter 文档 10.6 var subDeviceErrorCodes = map[uint64]string{ 0x10: "GeneralReject 诊断服务被拒绝", 0x11: "serviceNotSupported 不支持该诊断请求", 0x12: "subFunctionNotSupported 不支持该子功能", 0x13: "incorrectMessageLengthOrInvalidFormat 报文长度或格式错误", 0x14: "ResponseTooLong 响应过长", 0x22: "conditionsNotCorrect 条件错误", 0x23: "commTimeoutError 通信超时", 0x31: "requestOutOfRange 请求超过范围", 0x33: "securityAccessDenied 安全访问拒绝", 0x35: "invalidKey 密钥错误", 0x36: "exceedNumberOfAttempts 尝试次数超限", 0x37: "requiredTimeDelayNotExpired 延时未到期", 0x70: "UploadDownloadNotAccepted 上传或下载失败", 0x71: "TransferDataSuspended 数据传输中断", 0x72: "GeneralProgrammingFailure 擦写 Flash 错误", 0x73: "WrongBlockSequenceCounter 数据包序号错误", 0x78: "ResponsePending 子设备正忙", 0x7F: "serviceNotSupportedInActiveSession 当前模式不支持", } var fixedResultOne = map[string]string{ "ok": "成功", "cancomerr:time out": "与子设备通信超时", "emserr:can p null": "未取到目标子设备", "emserr:can data null": "子设备返回数据为空", "emserr:set cmd err": "下发命令失败", "emserr:other": "其他错误", } var errorReplyResults = map[string]string{ "json unpack err": "消息体不是合法 JSON", "cmd unpack err": "缺少 cmd 字段", "data unpack err": "缺少 data 字段", "busy": "设备正在处理其他命令", "pe sn not find": "pe 设备序列号无法匹配", "cmd no define": "不支持的命令码", "test fail": "连通性测试失败", } // DescribeResultOne 子项结果的中文说明,未知值原样返回 func DescribeResultOne(s string) string { if d, ok := fixedResultOne[s]; ok { return d } if v, ok := strings.CutPrefix(s, "cancomerr:suberrcode="); ok { return describeCode("子设备错误码", v, subDeviceErrorCodes) } if v, ok := strings.CutPrefix(s, "cancomerr:index="); ok { return describeCode("设备内部通信错误", v, internalErrorCodes) } return s } // DescribeReplyResult 379 整体结果的中文说明 func DescribeReplyResult(s string) string { switch s { case ResultOk: return "全部成功" case ResultError: return "存在失败的子项" } if d, ok := errorReplyResults[s]; ok { return d } return s } func describeCode(prefix, hexStr string, table map[uint64]string) string { code, err := strconv.ParseUint(strings.TrimPrefix(strings.ToLower(hexStr), "0x"), 16, 32) if err != nil { return fmt.Sprintf("%s %s", prefix, hexStr) } if d, ok := table[code]; ok { return fmt.Sprintf("%s 0x%X:%s", prefix, code, d) } return fmt.Sprintf("%s 0x%X", prefix, code) } // TriggerSourceName 触发源名称,表外代码返回空字符串 func TriggerSourceName(code uint16) string { return TriggerSourceNames[code] }