| | |
| | | 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) |
| | |
| | | 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 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 { |
| | |
| | | // 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) |
| | |
| | | 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) |
| | |
| | | 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 |
| | | |
| | |
| | | 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 { |
| | |
| | | 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 |
| | | } |