zhangqian
2023-09-12 b555874608be2e4bb40cceba60b497c04caef842
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package mitsubishi
 
import (
    "fmt"
    "strconv"
    "unicode"
)
 
// ProtocolMitsubishi 实现了 SerialProtocol 接口,用于三菱设备的串口通信
type ProtocolMitsubishi struct{}
 
// ConvertLabelToAddress 将设备特定的标签转换为寄存器地址
func (p *ProtocolMitsubishi) ConvertLabelToAddress(label string) string {
    if label[0] != 'D' {
        return ""
    }
    num := label[1:]
    for _, c := range num {
        if !unicode.IsDigit(c) {
            return ""
        }
    }
    var val int
    fmt.Sscanf(num, "%d", &val)
    vaddr := 0x1000 + val*2
    return fmt.Sprintf("%X", vaddr)
}
 
// MakeReadProtocol 创建读取数据的协议
func (p *ProtocolMitsubishi) MakeReadProtocol(addr string) []byte {
    // 02 表示开始 + 30 表示读数据 + 4位地址位 + 02 数据长度 + 03 停止 + 偶校验
 
    pro := []byte{0x30}
    pro = append(pro, []byte(addr)...)
    pro = append(pro, []byte("02")...)
    pro = append(pro, []byte{0x03}...)
 
    crc := crc(pro)
 
    proto := []byte{0x02}
    proto = append(proto, pro...)
    proto = append(proto, []byte(crc)...)
 
    return proto
}
 
// MakeWriteProtocol 创建写入数据的协议
func (p *ProtocolMitsubishi) MakeWriteProtocol(addr string, value int) []byte {
    valueStr := fmt.Sprintf("000%X", value)
    val := valueStr[len(valueStr)-2:]
    val += valueStr[len(valueStr)-4 : len(valueStr)-2]
 
    // 02 表示开始 + 31 表示写数据 + 4位地址位 + 02 数据长度 + 03 停止 + 偶校验
    pro := []byte{0x31}
    pro = append(pro, []byte(addr)...)
    pro = append(pro, []byte("02")...)
    pro = append(pro, val...)
    pro = append(pro, []byte{0x03}...)
 
    crc := crc(pro)
 
    proto := []byte{0x02}
    proto = append(proto, pro...)
    proto = append(proto, []byte(crc)...)
 
    return proto
}
 
// ParseReadValue 解析从设备读取的值
func (p *ProtocolMitsubishi) ParseReadValue(data []byte) int {
    if len(data) < 6 {
        return -1
    }
 
    vhex := data[1:5]
    v := vhex[2:]
    v = append(v, vhex[0:2]...)
    vstr := string(v)
 
    var bint int64
    bint, _ = strconv.ParseInt(vstr, 16, 32)
    return int(bint)
}
 
// ParseWriteValue 解析写入设备的结果
func (p *ProtocolMitsubishi) ParseWriteValue(data []byte) (v int, ok bool) {
    if len(data) == 0 {
        return -1, false
    }
 
    v = int(data[0])
    if v == 0x15 {
        // 失败
        return v, false
    }
    if v == 0x06 {
        // 成功
        return v, ok
    }
    return v, false
}
 
// crc 取后两位0x值
func crc(data []byte) string {
    // 计算校验码, 30 + 地址编码 + 数据长度 + 03 , 十六进制结果取后两位.
    var sum uint8
    for _, d := range data {
        sum += d
    }
 
    sumStr := fmt.Sprintf("0%X", sum)
    return sumStr[len(sumStr)-2:]
}