Skip to content

Commit 4178fa5

Browse files
committed
added Server T1S
1 parent 568b7ab commit 4178fa5

File tree

2 files changed

+547
-0
lines changed

2 files changed

+547
-0
lines changed

Diff for: src/ModbusT1SServer.cpp

+386
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
/*
2+
This file is part of the ArduinoModbus library.
3+
Copyright (c) 2018 Arduino SA. All rights reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
#if (defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_UNOR4_MINIMA))
20+
#include <errno.h>
21+
22+
extern "C" {
23+
#include "libmodbus/modbus.h"
24+
#include "libmodbus/modbus-rtu.h"
25+
}
26+
27+
#include "ModbusT1SServer.h"
28+
29+
size_t const UDP_RX_MSG_BUF_SIZE = 16 + 1;
30+
31+
/**
32+
* @class ModbusT1SServerClass
33+
* Class for Modbus T1S Server communication.
34+
*
35+
* This class provides functionalities to communicate with a Modbus T1S server.
36+
*/
37+
ModbusT1SServerClass::ModbusT1SServerClass()
38+
{
39+
}
40+
41+
/**
42+
* Constructor for ModbusT1SServerClass with RS485 support.
43+
*
44+
* Initializes the Modbus server with RS485 communication.
45+
*
46+
* @param rs485 Reference to an RS485Class object for RS485 communication.
47+
*/
48+
ModbusT1SServerClass::ModbusT1SServerClass(RS485Class& rs485) : _rs485(&rs485)
49+
{
50+
51+
}
52+
53+
/**
54+
* Destructor for ModbusT1SServerClass.
55+
*/
56+
ModbusT1SServerClass::~ModbusT1SServerClass()
57+
{
58+
}
59+
60+
/**
61+
* Initializes the Modbus server with the specified RS485 instance, baud rate, and configuration.
62+
*
63+
* This function sets up the Modbus server for communication using the specified RS485 instance, baud rate, and configuration.
64+
*
65+
* @param id (slave) id of the server
66+
* @param baudrate The baud rate for the Modbus communication.
67+
* @param config The configuration for the Modbus communication (e.g., parity, stop bits).
68+
* @return int Returns 1 if initialization is successful, 0 otherwise.
69+
*/
70+
int ModbusT1SServerClass::begin(int id, unsigned long baudrate, uint16_t config)
71+
{
72+
if(!ModbusRTUClient.begin(*_rs485, baudrate, config)) {
73+
return -1;
74+
}
75+
76+
ModbusRTUClient.setTimeout(2*1000UL);
77+
return 1;
78+
}
79+
80+
/**
81+
* Initializes the Modbus server with the specified RS485 instance, baud rate, and configuration.
82+
*
83+
* This function sets up the Modbus server for communication using the specified RS485 instance, baud rate, and configuration.
84+
*
85+
* @param rs485 Reference to an RS485Class object for RS485 communication.
86+
* @param id (slave) id of the server
87+
* @param baudrate The baud rate for the Modbus communication.
88+
* @param config The configuration for the Modbus communication (e.g., parity, stop bits).
89+
* @return int Returns 1 if initialization is successful, 0 otherwise.
90+
*/
91+
int ModbusT1SServerClass::begin(RS485Class& rs485, int id, unsigned long baudrate, uint16_t config)
92+
{
93+
_rs485 = &rs485;
94+
return begin(id, baudrate, config);
95+
}
96+
97+
/**
98+
* Initializes the Modbus server with the specified RS485 instance, baud rate, and configuration.
99+
*
100+
* This function sets up the Modbus server for communication using the specified RS485 instance, baud rate, and configuration.
101+
*
102+
* @param rs485 Reference to an RS485Class object for RS485 communication.
103+
* @param baudrate The baud rate for the Modbus communication.
104+
* @param config The configuration for the Modbus communication (e.g., parity, stop bits).
105+
* @return int Returns 1 if initialization is successful, 0 otherwise.
106+
*/
107+
int ModbusT1SServerClass::begin(RS485Class& rs485, unsigned long baudrate, uint16_t config)
108+
{
109+
_rs485 = &rs485;
110+
if(!ModbusRTUClient.begin(rs485, baudrate, config)) {
111+
return -1;
112+
}
113+
114+
ModbusRTUClient.setTimeout(2*1000UL);
115+
return 1;
116+
}
117+
118+
/**
119+
* Sets the Arduino_10BASE_T1S_UDP server for communication.
120+
*
121+
* This function sets the Arduino_10BASE_T1S_UDP server that the Modbus server will communicate with.
122+
*
123+
* @param server A pointer to the Arduino_10BASE_T1S_UDP server.
124+
*/
125+
int ModbusT1SServerClass::poll()
126+
{
127+
uint8_t request[MODBUS_RTU_MAX_ADU_LENGTH];
128+
129+
int requestLength = modbus_receive(_mb, request);
130+
131+
if (requestLength > 0) {
132+
modbus_reply(_mb, request, requestLength, &_mbMapping);
133+
return 1;
134+
}
135+
return 0;
136+
}
137+
138+
/**
139+
* Sets the Arduino_10BASE_T1S_UDP server for communication.
140+
*
141+
* This function sets the Arduino_10BASE_T1S_UDP server that the Modbus server will communicate with.
142+
*
143+
* @param server A pointer to the Arduino_10BASE_T1S_UDP server.
144+
*/
145+
int ModbusT1SServerClass::coilRead(int address)
146+
{
147+
int res = -1;
148+
if(_server == nullptr) {
149+
return res;
150+
}
151+
152+
int modbus_id = udp_rx_buf.at(2) << 8 | udp_rx_buf.at(3);
153+
int address_mod = udp_rx_buf.at(4) << 8 | udp_rx_buf.at(5);
154+
if(address != -1) {
155+
address_mod = address;
156+
}
157+
158+
if (ModbusRTUClient.requestFrom(modbus_id, COILS, address_mod, 1)) {
159+
if (ModbusRTUClient.available()) {
160+
res = ModbusRTUClient.read();
161+
udp_rx_buf.push_back((uint8_t)res);
162+
_server->beginPacket(_last_ip, _last_port);
163+
_server->write((uint8_t *)udp_rx_buf.data(), udp_rx_buf.size());
164+
_server->endPacket();
165+
}
166+
}
167+
udp_rx_buf.erase(udp_rx_buf.begin(), udp_rx_buf.end());
168+
return res;
169+
}
170+
171+
/**
172+
* Writes a value to a coil on the Modbus server.
173+
*
174+
* This function sends a request to write a value to a coil at the specified address
175+
* on the Modbus server using the provided UDP client.
176+
*
177+
* @param address The address of the coil to write to.
178+
* @param value The value to write to the coil (1 for ON, 0 for OFF).
179+
* @return int 1 if the write operation is successful, -1 if an error occurs.
180+
*/
181+
int ModbusT1SServerClass::coilWrite(int address, uint8_t value)
182+
{
183+
int res = -1;
184+
if(_server == nullptr) {
185+
return res;
186+
}
187+
188+
int modbus_id = udp_rx_buf.at(2) << 8 | udp_rx_buf.at(3);
189+
int address_mod = udp_rx_buf.at(4) << 8 | udp_rx_buf.at(5);
190+
if(address != -1) {
191+
address_mod = address;
192+
}
193+
uint8_t coilValue = int( udp_rx_buf.at(6));
194+
195+
ModbusRTUClient.beginTransmission(modbus_id, COILS, address_mod, 1);
196+
res = ModbusRTUClient.write(coilValue);
197+
if (!ModbusRTUClient.endTransmission()) {
198+
res = -1;
199+
}
200+
udp_rx_buf.erase(udp_rx_buf.begin(), udp_rx_buf.end());
201+
return res;
202+
}
203+
204+
/**
205+
* Reads the status of a discrete input from the Modbus server.
206+
*
207+
* This function sends a request to read the status of a discrete input at the specified address
208+
* from the Modbus server using the provided UDP client.
209+
*
210+
* @param address The address of the discrete input to read.
211+
* @return int The status of the discrete input (1 for ON, 0 for OFF) or -1 if an error occurs.
212+
*/
213+
int ModbusT1SServerClass::discreteInputRead(int address) {
214+
int res = -1;
215+
if(_server == nullptr) {
216+
return res;
217+
}
218+
219+
int modbus_id = udp_rx_buf.at(2) << 8 | udp_rx_buf.at(3);
220+
int address_mod = udp_rx_buf.at(4) << 8 | udp_rx_buf.at(5);
221+
if(address != -1) {
222+
address_mod = address;
223+
}
224+
225+
if (ModbusRTUClient.requestFrom(modbus_id, DISCRETE_INPUTS, address_mod, 1)) {
226+
if (ModbusRTUClient.available()) {
227+
res = ModbusRTUClient.read();
228+
udp_rx_buf.push_back((uint8_t)res);
229+
_server->beginPacket(_last_ip, _last_port);
230+
_server->write((uint8_t *)udp_rx_buf.data(), udp_rx_buf.size());
231+
_server->endPacket();
232+
}
233+
}
234+
udp_rx_buf.erase(udp_rx_buf.begin(), udp_rx_buf.end());
235+
return res;
236+
}
237+
238+
/**
239+
* Reads the value of an input register from the Modbus server.
240+
*
241+
* This function sends a request to read the value of an input register at the specified address
242+
* from the Modbus server using the provided UDP client.
243+
*
244+
* @param address The address of the input register to read.
245+
* @return long The value of the input register or -1 if an error occurs.
246+
*/
247+
long ModbusT1SServerClass::inputRegisterRead(int address)
248+
{
249+
long res = -1;
250+
if(_server == nullptr) {
251+
return res;
252+
}
253+
254+
int modbus_id = udp_rx_buf.at(2) << 8 | udp_rx_buf.at(3);
255+
int address_mod = udp_rx_buf.at(4) << 8 | udp_rx_buf.at(5);
256+
if(address != -1) {
257+
address_mod = address;
258+
}
259+
260+
if (ModbusRTUClient.requestFrom(modbus_id, INPUT_REGISTERS, address_mod, 1)) {
261+
if (ModbusRTUClient.available()) {
262+
int16_t data = ModbusRTUClient.read();
263+
uint8_t tx_buf[2] = {(uint8_t)((data & 0xFF00) >> 8), (uint8_t)(data & 0x00FF)};
264+
std::copy(tx_buf, tx_buf + 2, std::back_inserter(udp_rx_buf));
265+
_server->beginPacket(_last_ip, _last_port);
266+
_server->write((uint8_t *)udp_rx_buf.data(), udp_rx_buf.size());
267+
_server->endPacket();
268+
}
269+
}
270+
udp_rx_buf.erase(udp_rx_buf.begin(), udp_rx_buf.end());
271+
return res;
272+
}
273+
274+
/**
275+
* Writes a value to a holding register on the Modbus server.
276+
*
277+
* This function sends a request to write a value to a holding register at the specified address
278+
* on the Modbus server using the provided UDP client.
279+
*
280+
* @param address The address of the holding register to write to.
281+
* @param value The value to write to the holding register.
282+
* @return int 1 if the write operation is successful, -1 if an error occurs.
283+
*/
284+
long ModbusT1SServerClass::holdingRegisterRead(int address) {
285+
long res = -1;
286+
if(_server == nullptr) {
287+
return res;
288+
}
289+
290+
int modbus_id = udp_rx_buf.at(2) << 8 | udp_rx_buf.at(3);
291+
int address_mod = udp_rx_buf.at(4) << 8 | udp_rx_buf.at(5);
292+
if(address != -1) {
293+
address_mod = address;
294+
}
295+
296+
if (ModbusRTUClient.requestFrom(modbus_id, HOLDING_REGISTERS, address_mod, 1)) {
297+
if (ModbusRTUClient.available()) {
298+
int16_t data = ModbusRTUClient.read();
299+
uint8_t tx_buf[2] = {(uint8_t)((data & 0xFF00) >> 8), (uint8_t)(data & 0x00FF)};
300+
std::copy(tx_buf, tx_buf + 2, std::back_inserter(udp_rx_buf));
301+
_server->beginPacket(_last_ip, _last_port);
302+
_server->write((uint8_t *)udp_rx_buf.data(), udp_rx_buf.size());
303+
_server->endPacket();
304+
}
305+
}
306+
udp_rx_buf.erase(udp_rx_buf.begin(), udp_rx_buf.end());
307+
return res;
308+
}
309+
310+
/**
311+
* Writes a value to a holding register on the Modbus server.
312+
*
313+
* This function sends a request to write a value to a holding register at the specified address
314+
* on the Modbus server using the provided UDP client.
315+
*
316+
* @param address The address of the holding register to write to.
317+
* @param value The value to write to the holding register.
318+
* @return int 1 if the write operation is successful, -1 if an error occurs.
319+
*/
320+
int ModbusT1SServerClass::holdingRegisterWrite(int address) {
321+
int res = -1;
322+
if(_server == nullptr) {
323+
return res;
324+
}
325+
326+
int modbus_id = udp_rx_buf.at(2) << 8 | udp_rx_buf.at(3);
327+
int address_mod = udp_rx_buf.at(4) << 8 | udp_rx_buf.at(5);
328+
if(address != -1) {
329+
address_mod = address;
330+
}
331+
uint16_t value = udp_rx_buf.at(6) << 8 | udp_rx_buf.at(7);
332+
333+
ModbusRTUClient.beginTransmission(modbus_id, HOLDING_REGISTERS, address_mod, 1);
334+
res = ModbusRTUClient.write(value);
335+
if (!ModbusRTUClient.endTransmission()) {
336+
res = -1;
337+
}
338+
udp_rx_buf.erase(udp_rx_buf.begin(), udp_rx_buf.end());
339+
return res;
340+
}
341+
342+
/**
343+
* Parses the Modbus packet received from the server.
344+
*
345+
* This function parses the Modbus packet received from the server.
346+
*
347+
* @return int The parsed packet or -1 if an error occurs.
348+
*/
349+
int ModbusT1SServerClass::parsePacket() {
350+
int res = -1;
351+
if(_server == nullptr) {
352+
return res;
353+
}
354+
355+
int const rx_packet_size = _server->parsePacket();
356+
if (rx_packet_size)
357+
{
358+
uint8_t rx_msg_buf[UDP_RX_MSG_BUF_SIZE] = {0};
359+
int bytes_read = _server->read(rx_msg_buf, UDP_RX_MSG_BUF_SIZE - 1);
360+
while (bytes_read != 0) {
361+
std::copy(rx_msg_buf, rx_msg_buf + bytes_read, std::back_inserter(udp_rx_buf));
362+
bytes_read = _server->read(rx_msg_buf, UDP_RX_MSG_BUF_SIZE - 1);
363+
}
364+
res = udp_rx_buf.at(0) << 8 | udp_rx_buf.at(1);
365+
}
366+
367+
_last_ip = _server->remoteIP();
368+
_last_port = _server->remotePort();
369+
_server->flush();
370+
371+
return res;
372+
}
373+
374+
/**
375+
* Sets the Arduino_10BASE_T1S_UDP server for communication.
376+
*
377+
* This function sets the Arduino_10BASE_T1S_UDP server that the Modbus server will communicate with.
378+
*
379+
* @param server A pointer to the Arduino_10BASE_T1S_UDP server.
380+
*/
381+
void ModbusT1SServerClass::setT1SServer(Arduino_10BASE_T1S_UDP * server) {
382+
_server = server;
383+
}
384+
385+
ModbusT1SServerClass ModbusT1SServer;
386+
#endif

0 commit comments

Comments
 (0)