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
|
}
|
|
// MakeReadProtocolBits 三菱读协议, addr 是要读取的寄存器地址
|
func (p *ProtocolMitsubishi) MakeReadProtocolBits(bits int, addr string) []byte {
|
// 02 表示开始 + 30 表示读数据 + 4位地址位 + 02 数据长度 + 03 停止 + 偶校验
|
|
pro := []byte{0x30}
|
pro = append(pro, []byte(addr)...)
|
if bits == 16 {
|
pro = append(pro, []byte("02")...)
|
} else if bits == 32 {
|
pro = append(pro, []byte("04")...)
|
}
|
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
|
}
|
|
func (p *ProtocolMitsubishi) MakeWriteProtocolBits(bits int, addr string, ival int) []byte {
|
|
// 02 表示开始 + 31 表示写数据 + 4位地址位 + 02 数据长度 + 03 停止 + 偶校验
|
proto := []byte{0x31}
|
proto = append(proto, []byte(addr)...)
|
if bits == 16 {
|
proto = append(proto, []byte("02")...)
|
|
vstr := fmt.Sprintf("000%X", ival)
|
val := vstr[len(vstr)-2:]
|
val += vstr[len(vstr)-4 : len(vstr)-2]
|
proto = append(proto, val...)
|
} else if bits == 32 {
|
proto = append(proto, []byte("04")...)
|
|
vstr := fmt.Sprintf("0000000%X", ival)
|
// 低16位
|
low := vstr[len(vstr)-4:]
|
// 高16位
|
high := vstr[len(vstr)-8 : len(vstr)-4]
|
// 先存储低16位
|
val := low[2:]
|
val += low[0:2]
|
proto = append(proto, val...)
|
val = high[2:]
|
val += high[0:2]
|
proto = append(proto, val...)
|
}
|
|
proto = append(proto, []byte{0x03}...)
|
|
crc := crc(proto)
|
|
pro := []byte{0x02}
|
pro = append(pro, proto...)
|
pro = append(pro, []byte(crc)...)
|
|
return pro
|
}
|
|
// 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)
|
}
|
|
func (p *ProtocolMitsubishi) ParseReadValueBits(data []byte) int {
|
if len(data) < 6 {
|
return -1
|
}
|
|
// 0x2 [xxxxxxxx] 0x3 crc1 crc2
|
// 取出数据
|
|
fmt.Printf("ParseReadValueBits %X\n", data)
|
|
var num int64
|
vhex := data[1 : len(data)-3]
|
for i := len(vhex); i > 0; i -= 4 {
|
tmp := vhex[i-4 : i]
|
v := tmp[2:]
|
v = append(v, tmp[0:2]...)
|
var bint int64
|
|
bint, _ = strconv.ParseInt(string(v), 16, 32)
|
if num == 0 {
|
num = 0x10000 * bint
|
} else {
|
num += bint
|
}
|
}
|
|
// v := vhex[2:]
|
// v = append(v, vhex[0:2]...)
|
// vstr := string(v)
|
// var bint int64
|
// bint, _ = strconv.ParseInt(vstr, 16, 32)
|
|
return int(num)
|
}
|
|
// 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, true
|
}
|
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:]
|
}
|