| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- package faultRecordProtocol
- import (
- "encoding/binary"
- "encoding/hex"
- "fmt"
- "strings"
- )
- // 可配采样通道地址类型,FaultFilter 文档 5.4.1 id=6;名称统一首字母大写
- var ChannelAddrTypeNames = map[uint8]string{
- 0x0: "Empty",
- 0x1: "Uint16",
- 0x2: "Int16",
- 0x3: "Float32",
- 0x4: "Uint32_HWord",
- 0x5: "Uint32_LWord",
- 0x6: "Uint32",
- }
- // DecodeHex 解码十六进制字符串(允许空格)
- func DecodeHex(s string) ([]byte, error) {
- s = strings.ReplaceAll(strings.TrimSpace(s), " ", "")
- if len(s)%2 != 0 {
- return nil, fmt.Errorf("hex length must be even")
- }
- return hex.DecodeString(s)
- }
- // ValidateSetVal 按功能码校验 setVal 的字节长度和取值
- func ValidateSetVal(id int, setVal string) error {
- b, err := DecodeHex(setVal)
- if err != nil {
- return fmt.Errorf("id=%d setVal invalid: %w", id, err)
- }
- switch id {
- case 1, 3:
- if len(b) != 0 {
- return fmt.Errorf("id=%d takes no parameter", id)
- }
- case 2:
- if len(b) < 1 || (len(b)-1)%2 != 0 {
- return fmt.Errorf("id=2 setVal must be 1 byte count + n × 2 bytes")
- }
- case 4:
- if len(b) != 7 {
- return fmt.Errorf("id=4 setVal must be 7 bytes")
- }
- case 5:
- if len(b) != 2 {
- return fmt.Errorf("id=5 setVal must be 2 bytes")
- }
- case 6:
- if len(b) != 6 {
- return fmt.Errorf("id=6 setVal must be 6 bytes")
- }
- case 7:
- if len(b) != 1 || b[0] > 1 {
- return fmt.Errorf("id=7 setVal must be 00 or 01")
- }
- default:
- return fmt.Errorf("invalid function code %d", id)
- }
- return nil
- }
- // ConfigChannel id=6 可配采样通道配置
- type ConfigChannel struct {
- Index uint8 `json:"index"`
- Mode uint8 `json:"mode"` // 0=默认方式(地址),1=代码方式
- AddrType uint8 `json:"addrType"` // 默认方式下的地址类型
- TypeName string `json:"typeName,omitempty"`
- Address uint32 `json:"address,omitempty"` // 默认方式
- Code uint16 `json:"code,omitempty"` // 代码方式
- }
- // DecodeIdData 解读 cmd=3 返回的 idData(结构参照对应功能码的 setVal)。
- // 无法解读时返回 nil,调用方只显示原始值。
- func DecodeIdData(id int, idData string) any {
- b, err := DecodeHex(idData)
- if err != nil {
- return nil
- }
- switch id {
- case 2:
- if len(b) < 1 || (len(b)-1)%2 != 0 {
- return nil
- }
- channels := make([]string, 0, (len(b)-1)/2)
- for i := 1; i+1 < len(b); i += 2 {
- channels = append(channels, fmt.Sprintf("0x%04X", binary.BigEndian.Uint16(b[i:])))
- }
- return map[string]any{"count": b[0], "channels": channels}
- case 4:
- if len(b) != 7 {
- return nil
- }
- return map[string]any{"deviceTime": ParseDeviceTime(b).String()}
- case 5:
- if len(b) != 2 {
- return nil
- }
- return map[string]any{"frequencyHz": binary.BigEndian.Uint16(b)}
- case 6:
- if len(b) != 6 {
- return nil
- }
- c := ConfigChannel{Index: b[0], Mode: b[1] >> 4, AddrType: b[1] & 0x0F}
- if c.Mode == 0 {
- c.TypeName = ChannelAddrTypeNames[c.AddrType]
- c.Address = binary.BigEndian.Uint32(b[2:])
- } else {
- c.Code = binary.BigEndian.Uint16(b[2:])
- }
- return c
- case 7:
- if len(b) != 1 {
- return nil
- }
- return map[string]any{"enabled": b[0] == 1}
- }
- return nil
- }
- // DeviceTime 设备时间(7 字节:年 2B 大端、月、日、时、分、秒),按设备时间原样表示,不做时区换算
- type DeviceTime struct {
- Year uint16 `json:"year"`
- Month uint8 `json:"month"`
- Day uint8 `json:"day"`
- Hour uint8 `json:"hour"`
- Min uint8 `json:"min"`
- Sec uint8 `json:"sec"`
- }
- func ParseDeviceTime(b []byte) DeviceTime {
- return DeviceTime{
- Year: binary.BigEndian.Uint16(b[0:2]),
- Month: b[2],
- Day: b[3],
- Hour: b[4],
- Min: b[5],
- Sec: b[6],
- }
- }
- func (t DeviceTime) String() string {
- return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", t.Year, t.Month, t.Day, t.Hour, t.Min, t.Sec)
- }
|