fix
zhangqian
2023-12-01 8324f872ef3a4d0c978a9b1d062800c6a1701c12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package plccom
 
import (
    "apsClient/pkg/logx"
    "apsClient/pkg/plccom/mitsubishi"
    "encoding/base64"
    "errors"
    "fmt"
    "io"
    "net/http"
    "strings"
)
 
// SerialProtocol 是串口通信协议的通用接口
type SerialProtocol interface {
    // ConvertLabelToAddress 将设备特定的标签转换为寄存器地址
    ConvertLabelToAddress(label string) string
 
    // 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)
}
 
const (
    DeviceTypeMitsubishi = "mitsubishi"
)
 
// LoadProtocol 根据配置加载不同的协议实现
func LoadProtocol(deviceType string) (SerialProtocol, error) {
    var protocol SerialProtocol
 
    switch deviceType {
    case DeviceTypeMitsubishi:
        protocol = &mitsubishi.ProtocolMitsubishi{} // 使用三菱设备协议
    // case "OtherDevice":
    //     protocol = &OtherDeviceProtocol{} // 使用其他设备的协议
    default:
        return nil, fmt.Errorf("unsupported device type: %s", deviceType)
    }
 
    return protocol, nil
}
 
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)
    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)
    if err != nil {
        logx.Errorf("ReadPLC http get failed:%v", err)
        return 0, err
    }
    body := readBody(resp.Body)
    data, err := base64.StdEncoding.DecodeString(string(body))
    if err != nil {
        logx.Errorf("ReadPLC base64.StdEncoding.DecodeString failed: %v, data: %v", err, string(body))
        return 0, err
    }
    if length == 1 {
        val = protocol.ParseReadValue(data)
    } else {
        val = protocol.ParseReadValueBits(data)
    }
 
    fmt.Println("read PLC:", val)
    return val, nil
 
}
 
func readBody(r io.ReadCloser) []byte {
    body, e := io.ReadAll(r)
    defer r.Close()
    if e != nil {
        fmt.Println("ReadAll resp body error:", e)
        return nil
    }
    return body
}
 
func WritePLC(deviceType, url, label string, val int) error {
    protocol, err := LoadProtocol(deviceType)
    if err != nil {
        return err
    }
    addr := protocol.ConvertLabelToAddress(label)
    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 {
        logx.Errorf("write plc http post failed:%v", err)
        return err
    }
    body := readBody(resp.Body)
    data, err := base64.StdEncoding.DecodeString(string(body))
    if err != nil {
        logx.Errorf("write plc base64 StdEncoding DecodeString:%v", err)
        return err
    }
    val, ok := protocol.ParseWriteValue(data)
    if !ok {
        logx.Errorf("serial write failed, response:%v", val)
        return errors.New("failed")
    }
    logx.Errorf("serial write success, response:%v", val)
    return nil
}