-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.go
160 lines (134 loc) · 3.6 KB
/
server.go
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package engcore_modbus
import (
"fmt"
"log"
"net"
)
type ModbusServer struct {
ip net.IP
port int
mbMap *ModbusRegisters
action [17]func([]byte, *ModbusRegisters) ([]byte, error)
}
func NewModbusServer(ip string, port int, mMap *ModbusRegisters) *ModbusServer {
m := &ModbusServer{}
log.Println("create new modbus server instance")
ipV4Adr, _, netparserr := net.ParseCIDR(ip)
if netparserr != nil {
log.Fatalln("invalid ip adress")
}
m.ip = ipV4Adr
m.port = port
m.mbMap = mMap
m.action[1] = readCoilStatus
m.action[2] = readInputStatus
m.action[3] = readHoldingRegisters
m.action[4] = readInputRegister
m.action[5] = forseSingleCoil
m.action[6] = presetSingleRegister
m.action[15] = forseMultipalCoil
m.action[16] = presetMultipalRegister
log.Println("add modbus function to action list")
return m
}
func (m *ModbusServer) StartServer() {
ls, err := net.ListenTCP("tcp4", &net.TCPAddr{
Port: m.port,
IP: m.ip,
})
if err != nil {
log.Println(err.Error())
}
log.Printf("server was started. %v", ls.Addr())
for {
conn, err := ls.Accept()
if err != nil {
fmt.Errorf("%v\n", err.Error())
}
//Client
go m.handlerClient(conn)
}
}
func (m *ModbusServer) handlerClient(conn net.Conn) {
defer func() {
log.Printf("Connection was closed")
conn.Close()
recover()
}()
log.Printf("Connected: %v", conn.RemoteAddr())
buffer := make([]byte, 2048)
for {
length, err := conn.Read(buffer)
if err != nil {
fmt.Errorf("%v reading error %v", conn.RemoteAddr(), err.Error())
continue
}
log.Printf("message length is: %v\n", length)
bufferData := buffer[:length]
frame, err := RawDataToModbusRawData(bufferData)
if err != nil {
log.Println(err.Error())
continue
}
fmt.Printf("Request frame:%v", frame)
if frame.FunctionalCode > 17 {
result, err := errorResponce(&frame)
if err != nil {
log.Println(err.Error())
continue
}
lenrcv, err := conn.Write(result)
if err != nil || lenrcv <= 0 {
log.Println("error send recive with illegal functional code error", err.Error())
continue
}
continue
}
log.Printf("functional code is: %v", frame.FunctionalCode)
result, err := m.action[frame.FunctionalCode](frame.Data, m.mbMap)
log.Println("Result:", result)
//Unlock
if err != nil {
log.Println(err.Error())
frame.FunctionalCode = frame.FunctionalCode + 128
}
responceframe, err := createResponce(&frame, result)
log.Println("Responce Frame:", responceframe)
butesresult, err := responceframe.ModbusFrametoByteSlice()
log.Println(butesresult)
lenRcv, WriteError := conn.Write(butesresult)
if WriteError != nil {
fmt.Errorf(WriteError.Error())
continue
}
if lenRcv == 0 {
log.Default().Output(0, "Wweeeeee")
}
}
}
func createResponce(request *ModbusRawData, data []byte) (*ModbusRawData, error) {
responce := &ModbusRawData{}
responce.TransactionID = request.TransactionID
responce.ProtocolID = request.ProtocolID
responce.Length = (uint16)(len(data) + 2)
responce.UnitID = request.UnitID
responce.FunctionalCode = request.FunctionalCode
responce.Data = data
return responce, nil
}
func errorResponce(request *ModbusRawData) ([]byte, error) {
request.FunctionalCode = request.FunctionalCode + 128
responce, err := createResponce(request, []byte{ILLEGAL_FUNCTION})
if err != nil {
log.Println("create pesponce err")
return nil, err
}
log.Println("Responceframe:", responce)
result, err := responce.ModbusFrametoByteSlice()
if err != nil {
log.Println("error convert modbus framme to byte slice")
return nil, err
}
log.Println("Responce byte slice:", result)
return result, nil
}