-
Notifications
You must be signed in to change notification settings - Fork 4
/
client.go
182 lines (159 loc) · 5.13 KB
/
client.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Copyright 2019 Sergey Soldatov. All rights reserved.
// This software may be modified and distributed under the terms
// of the Apache license. See the LICENSE file for details.
package modbus
import (
"fmt"
"log"
"math"
"net"
)
// ModbusClient implements client interface
type ModbusClient struct {
ModbusBaseClient
DevID byte
TypeProtocol ModbusTypeProtocol // Type Modbus Protocol
Conn net.Conn // Connection
TranscationId uint16 // for ModbusTCP
}
// NewClient function initializate new instance of ModbusClient
func NewClient(port, host string, mbprotocol ModbusTypeProtocol, devID byte) (*ModbusClient, error) {
var err error
mc := &ModbusClient{TypeProtocol: mbprotocol, DevID: devID}
mc.Host = host
mc.Port = port
mc.Conn, err = net.Dial("tcp", mc.String())
return mc, err
}
// Read Answer from Slave device (Server)
func (mc *ModbusClient) ReadAnswer() (*ModbusPacket, error) {
var err error
answer := &ModbusPacket{isAnswer: true}
answer.Init(mc.TypeProtocol)
log.Printf(
"Src->: %s Dst<-: %s\n",
mc.Conn.RemoteAddr(),
mc.Conn.LocalAddr())
// Read the incoming connection into the buffer.
answer.Length, err = mc.Conn.Read(answer.PDU)
if err != nil {
log.Println("Error reading:", err.Error())
}
return answer, err
}
// Send Request to Slave device (Server) and return Answer from it
func (mc *ModbusClient) SendRequest(mp *ModbusPacket) (*ModbusPacket, error) {
var err error
log.Println("Send request to", mc)
_, err = mc.Conn.Write(mp.PDU[:mp.GetPDULength()])
if err != nil {
log.Println("Error connect:", err.Error())
return nil, err
}
return mc.ReadAnswer()
}
// Send Request ReadHoldingRegisters
func (mc *ModbusClient) ReadHoldingRegisters(addr, cnt uint16) ([]uint16, error) {
request := buildRequest(mc.GetTransactionId(), mc.TypeProtocol, mc.DevID, FcReadHoldingRegisters, addr, cnt)
answer, err := mc.SendRequest(request)
if err != nil {
return nil, err
}
_, data := answer.GetData()
return byteArrToWordArr(data), nil
}
// Send Request ReadInputRegisters
func (mc *ModbusClient) ReadInputRegisters(addr, cnt uint16) ([]uint16, error) {
request := buildRequest(mc.GetTransactionId(), mc.TypeProtocol, mc.DevID, FcReadInputRegisters, addr, cnt)
answer, err := mc.SendRequest(request)
if err != nil {
return nil, err
}
_, data := answer.GetData()
return byteArrToWordArr(data), nil
}
// Send Request PresetSingleRegister
func (mc *ModbusClient) PresetSingleRegister(addr, value uint16) error {
request := buildRequest(mc.GetTransactionId(), mc.TypeProtocol, mc.DevID, FcReadInputRegisters, addr, value)
answer, err := mc.SendRequest(request)
if err != nil {
return err
}
if byte(answer.GetFunctionCode())&0x80 > 0 {
return fmt.Errorf("Error code %x", answer.GetErrorCode())
}
return nil
}
// Send Request ReadCoilStatus
func (mc *ModbusClient) ReadCoilStatus(addr, cnt uint16) ([]bool, error) {
request := buildRequest(mc.GetTransactionId(), mc.TypeProtocol, mc.DevID, FcReadCoilStatus, addr, cnt)
answer, err := mc.SendRequest(request)
if err != nil {
return nil, err
}
_, data := answer.GetData()
return byteArrToBoolArr(data, byte(cnt)), nil
}
// Send Request ReadCoilStatus
func (mc *ModbusClient) ReadDescreteInputs(addr, cnt uint16) ([]bool, error) {
request := buildRequest(mc.GetTransactionId(), mc.TypeProtocol, mc.DevID, FcReadDescreteInputs, addr, cnt)
answer, err := mc.SendRequest(request)
if err != nil {
return nil, err
}
_, data := answer.GetData()
return byteArrToBoolArr(data, byte(cnt)), nil
}
// Send Request ForceSingleCoil
func (mc *ModbusClient) ForceSingleCoil(addr uint16, value bool) error {
v := uint16(0)
if value {
v = 0xFF00
}
request := buildRequest(mc.GetTransactionId(), mc.TypeProtocol, mc.DevID, FcForceSingleCoil, addr, v)
answer, err := mc.SendRequest(request)
if err != nil {
return err
}
if byte(answer.GetFunctionCode())&0x80 > 0 {
return fmt.Errorf("Error code %x", answer.GetErrorCode())
}
return nil
}
// Send Request PresetMultipleRegisters
func (mc *ModbusClient) PresetMultipleRegisters(addr, cnt uint16, data ...uint16) error {
request := buildRequest(mc.GetTransactionId(), mc.TypeProtocol, mc.DevID, FcPresetMultipleRegisters, addr, cnt, wordArrToByteArr(data)...)
answer, err := mc.SendRequest(request)
if err != nil {
return err
}
if byte(answer.GetFunctionCode())&0x80 > 0 {
return fmt.Errorf("Error code %x", answer.GetErrorCode())
}
return nil
}
// Send Request ForceMultipleCoils
func (mc *ModbusClient) ForceMultipleCoils(addr, cnt uint16, data ...bool) error {
request := buildRequest(mc.GetTransactionId(), mc.TypeProtocol, mc.DevID, FcForceMultipleCoils, addr, cnt, boolArrToByteArr(data)...)
answer, err := mc.SendRequest(request)
if err != nil {
return err
}
if byte(answer.GetFunctionCode())&0x80 > 0 {
return fmt.Errorf("Error code %x", answer.GetErrorCode())
}
return nil
}
// Close client
func (mc *ModbusClient) Close() {
// Close the connection when you're done with it.
mc.Conn.Close()
}
// Get Transaction ID
func (mc *ModbusClient) GetTransactionId() uint16 {
mc.TranscationId++
if mc.TranscationId == math.MaxUint16 {
mc.TranscationId = 0
}
return mc.TranscationId
}