setval.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package faultRecordProtocol
  2. import (
  3. "encoding/binary"
  4. "encoding/hex"
  5. "fmt"
  6. "strings"
  7. )
  8. // 可配采样通道地址类型,FaultFilter 文档 5.4.1 id=6;名称统一首字母大写
  9. var ChannelAddrTypeNames = map[uint8]string{
  10. 0x0: "Empty",
  11. 0x1: "Uint16",
  12. 0x2: "Int16",
  13. 0x3: "Float32",
  14. 0x4: "Uint32_HWord",
  15. 0x5: "Uint32_LWord",
  16. 0x6: "Uint32",
  17. }
  18. // DecodeHex 解码十六进制字符串(允许空格)
  19. func DecodeHex(s string) ([]byte, error) {
  20. s = strings.ReplaceAll(strings.TrimSpace(s), " ", "")
  21. if len(s)%2 != 0 {
  22. return nil, fmt.Errorf("hex length must be even")
  23. }
  24. return hex.DecodeString(s)
  25. }
  26. // ValidateSetVal 按功能码校验 setVal 的字节长度和取值
  27. func ValidateSetVal(id int, setVal string) error {
  28. b, err := DecodeHex(setVal)
  29. if err != nil {
  30. return fmt.Errorf("id=%d setVal invalid: %w", id, err)
  31. }
  32. switch id {
  33. case 1, 3:
  34. if len(b) != 0 {
  35. return fmt.Errorf("id=%d takes no parameter", id)
  36. }
  37. case 2:
  38. if len(b) < 1 || (len(b)-1)%2 != 0 {
  39. return fmt.Errorf("id=2 setVal must be 1 byte count + n × 2 bytes")
  40. }
  41. case 4:
  42. if len(b) != 7 {
  43. return fmt.Errorf("id=4 setVal must be 7 bytes")
  44. }
  45. case 5:
  46. if len(b) != 2 {
  47. return fmt.Errorf("id=5 setVal must be 2 bytes")
  48. }
  49. case 6:
  50. if len(b) != 6 {
  51. return fmt.Errorf("id=6 setVal must be 6 bytes")
  52. }
  53. case 7:
  54. if len(b) != 1 || b[0] > 1 {
  55. return fmt.Errorf("id=7 setVal must be 00 or 01")
  56. }
  57. default:
  58. return fmt.Errorf("invalid function code %d", id)
  59. }
  60. return nil
  61. }
  62. // ConfigChannel id=6 可配采样通道配置
  63. type ConfigChannel struct {
  64. Index uint8 `json:"index"`
  65. Mode uint8 `json:"mode"` // 0=默认方式(地址),1=代码方式
  66. AddrType uint8 `json:"addrType"` // 默认方式下的地址类型
  67. TypeName string `json:"typeName,omitempty"`
  68. Address uint32 `json:"address,omitempty"` // 默认方式
  69. Code uint16 `json:"code,omitempty"` // 代码方式
  70. }
  71. // DecodeIdData 解读 cmd=3 返回的 idData(结构参照对应功能码的 setVal)。
  72. // 无法解读时返回 nil,调用方只显示原始值。
  73. func DecodeIdData(id int, idData string) any {
  74. b, err := DecodeHex(idData)
  75. if err != nil {
  76. return nil
  77. }
  78. switch id {
  79. case 2:
  80. if len(b) < 1 || (len(b)-1)%2 != 0 {
  81. return nil
  82. }
  83. channels := make([]string, 0, (len(b)-1)/2)
  84. for i := 1; i+1 < len(b); i += 2 {
  85. channels = append(channels, fmt.Sprintf("0x%04X", binary.BigEndian.Uint16(b[i:])))
  86. }
  87. return map[string]any{"count": b[0], "channels": channels}
  88. case 4:
  89. if len(b) != 7 {
  90. return nil
  91. }
  92. return map[string]any{"deviceTime": ParseDeviceTime(b).String()}
  93. case 5:
  94. if len(b) != 2 {
  95. return nil
  96. }
  97. return map[string]any{"frequencyHz": binary.BigEndian.Uint16(b)}
  98. case 6:
  99. if len(b) != 6 {
  100. return nil
  101. }
  102. c := ConfigChannel{Index: b[0], Mode: b[1] >> 4, AddrType: b[1] & 0x0F}
  103. if c.Mode == 0 {
  104. c.TypeName = ChannelAddrTypeNames[c.AddrType]
  105. c.Address = binary.BigEndian.Uint32(b[2:])
  106. } else {
  107. c.Code = binary.BigEndian.Uint16(b[2:])
  108. }
  109. return c
  110. case 7:
  111. if len(b) != 1 {
  112. return nil
  113. }
  114. return map[string]any{"enabled": b[0] == 1}
  115. }
  116. return nil
  117. }
  118. // DeviceTime 设备时间(7 字节:年 2B 大端、月、日、时、分、秒),按设备时间原样表示,不做时区换算
  119. type DeviceTime struct {
  120. Year uint16 `json:"year"`
  121. Month uint8 `json:"month"`
  122. Day uint8 `json:"day"`
  123. Hour uint8 `json:"hour"`
  124. Min uint8 `json:"min"`
  125. Sec uint8 `json:"sec"`
  126. }
  127. func ParseDeviceTime(b []byte) DeviceTime {
  128. return DeviceTime{
  129. Year: binary.BigEndian.Uint16(b[0:2]),
  130. Month: b[2],
  131. Day: b[3],
  132. Hour: b[4],
  133. Min: b[5],
  134. Sec: b[6],
  135. }
  136. }
  137. func (t DeviceTime) String() string {
  138. return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", t.Year, t.Month, t.Day, t.Hour, t.Min, t.Sec)
  139. }