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