You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
4.9 KiB

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 := &params.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 := &params.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)
}