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:]
|
}
|