package m9z import ( "encoding/binary" "fmt" "github.com/gogf/gf/v2/util/gconv" ) // LoopCommonParameters 回路分控器公共参数结构体 (15个寄存器 = 30字节) type LoopCommonParameters struct { DCVoltage float32 // 直流电压 (0.1V单位) DCCurrent float32 // 直流电流 (0.1A单位) DimmingValue float32 // 调光幅度值 (0-100%) AlarmStatus uint16 // 告警状态 (位图形式) 告警状态寄存器 0x01欠压 0x02过压 0x08电源故障 其中:欠压=短路故障,过压=开路故障,电源故障。 AlarmCode string // 告警代码 RelayStatus uint16 // 继电器状态 (位图形式) LoopAddress string // 回路地址 SubModuleCount uint16 // 子模块数量 Reserved [14]byte // 备用字段 (7个寄存器=14字节) } // LoopModuleParameters 回路子模块参数结构体 (13个寄存器 = 26字节) type LoopModuleParameters struct { OutputVoltage float32 // 模块输出电压值 (0.1V) OutputCurrent float32 // 模块输出电流值 (0.01A) CurrentPWMDuty float32 // 模块电流PWM占空比 (0-10000对应0-100%) VoltagePWMDuty float32 // 模块电压PWM占空比 (0-10000对应0-100%) DeviceAddress string // 模块的设备地址 ModuleLoopAddress string // 模块的回路地址 CurrentLimitPct float32 // 模块的限流百分数 (0-100对应0-100%) OperatingMode uint16 // 模块手动/自动模式 (0=自动,1=手动) ModuleVersion float32 // 模块的版本号 RatedVoltageDuty uint16 // 额定配置电压PWM占空比 (0-10000对应0-100%) RatedCurrentDuty uint16 // 额定配置电流PWM占空比 (0-10000对应0-100%) RatedOutputVoltage uint16 // 额定配置输出电压值 (0.1V) RatedOutputCurrent uint16 // 额定配置输出电流值 (0.01A) } // LoopFullParameters 完整回路参数数据结构 type LoopFullParameters struct { LoopCommonParameters // 公共参数 (30字节) Modules []LoopModuleParameters // 8个模块的参数 (208字节) } // ParseLoopFullParameters 解析完整的238字节分控器数据 func ParseLoopFullParameters(data []byte) (*LoopFullParameters, error) { if len(data) < 238 { return nil, fmt.Errorf("invalid data length %d, expected 238 bytes", len(data)) } params := &LoopFullParameters{} offset := 0 // 解析公共参数区 (30字节) common := ¶ms.LoopCommonParameters common.DCVoltage = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1 offset += 2 common.DCCurrent = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1 offset += 2 common.DimmingValue = float32(binary.LittleEndian.Uint16(data[offset:])) * 10 * 0.01 offset += 2 //log.Debugf("AlarmStatus [% X]", data) common.AlarmStatus = uint16(data[offset:][0]) common.AlarmCode = fmt.Sprintf("% X", data[offset:offset+2]) offset += 2 common.RelayStatus = binary.LittleEndian.Uint16(data[offset:]) offset += 2 if binary.LittleEndian.Uint16(data[offset:]) == 0 { return nil, nil } common.LoopAddress = fmt.Sprintf("0x%x", binary.LittleEndian.Uint16(data[offset:])) offset += 2 common.SubModuleCount = binary.LittleEndian.Uint16(data[offset:]) offset += 2 copy(common.Reserved[:], data[offset:offset+16]) offset += 16 params.Modules = make([]LoopModuleParameters, common.SubModuleCount) // 解析8个模块 (每个26字节) for i := 0; i < int(common.SubModuleCount); i++ { module := ¶ms.Modules[i] module.OutputVoltage = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1 offset += 2 module.OutputCurrent = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1 offset += 2 module.CurrentPWMDuty = float32(binary.LittleEndian.Uint16(data[offset:])) * 10 * 0.01 offset += 2 module.VoltagePWMDuty = float32(binary.LittleEndian.Uint16(data[offset:])) * 10 * 0.01 offset += 2 module.DeviceAddress = fmt.Sprintf("0x%x", binary.LittleEndian.Uint16(data[offset:])) offset += 2 module.ModuleLoopAddress = fmt.Sprintf("0x%x", binary.LittleEndian.Uint16(data[offset:])) offset += 2 module.CurrentLimitPct = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1 offset += 2 module.OperatingMode = binary.LittleEndian.Uint16(data[offset:]) offset += 2 version := fmt.Sprintf("%x", binary.LittleEndian.Uint16(data[offset:])) floatVersion := gconv.Float32(version) module.ModuleVersion = floatVersion * 0.1 offset += 2 module.RatedVoltageDuty = binary.LittleEndian.Uint16(data[offset:]) offset += 2 module.RatedCurrentDuty = binary.LittleEndian.Uint16(data[offset:]) offset += 2 module.RatedOutputVoltage = binary.LittleEndian.Uint16(data[offset:]) offset += 2 module.RatedOutputCurrent = binary.LittleEndian.Uint16(data[offset:]) offset += 2 } return params, nil } func SubLoopParametersRead(device string, idx uint) (*LoopFullParameters, error) { readRep, err := ReadCmd(device, subLoopParameters, "读取回路分控器的参数", idx) if err != nil { return nil, err } return ParseLoopFullParameters(readRep.Data) }