zhangqian
2023-11-03 7335d19846ad4f5b0a61541a992d61763c5cf35b
串口支持大数读写
3个文件已修改
131 ■■■■■ 已修改文件
pkg/plccom/mitsubishi/protocol.go 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/plccom/plccom.go 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/plc.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/plccom/mitsubishi/protocol.go
@@ -44,6 +44,28 @@
    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)
@@ -66,6 +88,46 @@
    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 {
@@ -82,6 +144,41 @@
    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 {
pkg/plccom/plccom.go
@@ -19,11 +19,18 @@
    // MakeReadProtocol 创建读取数据的协议
    MakeReadProtocol(addr string) []byte
    // MakeReadProtocolBits 创建读取数据的协议
    MakeReadProtocolBits(bits int, addr string) []byte
    // MakeWriteProtocol 创建写入数据的协议
    MakeWriteProtocol(addr string, value int) []byte
    MakeWriteProtocolBits(bits int, addr string, ival int) []byte
    // ParseReadValue 解析从设备读取的值
    ParseReadValue(data []byte) int
    ParseReadValueBits(data []byte) int
    // ParseWriteValue 解析写入设备的结果,并返回结果和是否成功
    ParseWriteValue(data []byte) (int, bool)
@@ -49,13 +56,19 @@
    return protocol, nil
}
func ReadPLC(deviceType, url, label string) (val int, err error) {
func ReadPLC(deviceType, url, label string, length int) (val int, err error) {
    protocol, err := LoadProtocol(deviceType)
    if err != nil {
        return 0, err
    }
    addr := protocol.ConvertLabelToAddress(label)
    proto := protocol.MakeReadProtocol(addr)
    var proto []byte
    if length == 1 {
        proto = protocol.MakeReadProtocol(addr)
    } else {
        proto = protocol.MakeReadProtocolBits(length*16, addr)
    }
    bp := base64.StdEncoding.EncodeToString(proto)
    fullUrl := fmt.Sprintf("%v?proto=%v", url, bp)
    resp, err := http.Get(fullUrl)
@@ -69,7 +82,12 @@
        logx.Errorf("ReadPLC base64.StdEncoding.DecodeString failed: %v, data: %v", err, string(body))
        return 0, err
    }
    val = protocol.ParseReadValue(data)
    if length == 1 {
        val = protocol.ParseReadValue(data)
    } else {
        val = protocol.ParseReadValueBits(data)
    }
    fmt.Println("read PLC:", val)
    return val, nil
@@ -91,7 +109,13 @@
        return err
    }
    addr := protocol.ConvertLabelToAddress(label)
    proto := protocol.MakeWriteProtocol(addr, val)
    var proto []byte
    if val < 65536 {
        proto = protocol.MakeWriteProtocol(addr, val)
    } else {
        proto = protocol.MakeWriteProtocolBits(32, addr, val)
    }
    bp := base64.StdEncoding.EncodeToString(proto)
    resp, err := http.Post(url, "text/plain", strings.NewReader(bp))
    if err != nil {
service/plc.go
@@ -112,7 +112,7 @@
            return nil, errors.New("conf.Conf.Services.Serial config not set yet")
        }
        label := fmt.Sprintf("D%d", address)
        return plccom.ReadPLC(plccom.DeviceTypeMitsubishi, ipAddr, label)
        return plccom.ReadPLC(plccom.DeviceTypeMitsubishi, ipAddr, label, dataLength)
    }
    return
}