zhangqian
2023-09-07 d4272e1b692515af9c47799a658e395703d13555
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
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
 
    // MakeWriteProtocol 创建写入数据的协议
    MakeWriteProtocol(addr string, value int) []byte
 
    // ParseReadValue 解析从设备读取的值
    ParseReadValue(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) (val int, err error) {
    protocol, err := LoadProtocol(deviceType)
    if err != nil {
        return 0, err
    }
    addr := protocol.ConvertLabelToAddress(label)
    proto := protocol.MakeReadProtocol(addr)
    bp := base64.StdEncoding.EncodeToString(proto)
 
    resp, err := http.Get(url + bp)
    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", err)
        return 0, err
    }
    val = protocol.ParseReadValue(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)
    proto := protocol.MakeWriteProtocol(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
}