Skip to content

Commit 7997cf9

Browse files
committed
added methods to configure modbus server to existing data stuctures
1 parent f912539 commit 7997cf9

File tree

3 files changed

+229
-0
lines changed

3 files changed

+229
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
Ethernet Modbus TCP Server LED using existing variables as modbus memory
3+
4+
This sketch creates a Modbus TCP Server with a simulated coil.
5+
The value of the simulated coil is set on the LED
6+
7+
Circuit:
8+
- Any Arduino MKR Board
9+
- MKR ETH Shield
10+
11+
created 16 July 2018
12+
by Sandeep Mistry
13+
*/
14+
15+
#include <SPI.h>
16+
#include <Ethernet.h>
17+
18+
#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
19+
#include <ArduinoModbus.h>
20+
21+
// Enter a MAC address for your controller below.
22+
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
23+
// The IP address will be dependent on your local network:
24+
byte mac[] = {
25+
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
26+
};
27+
IPAddress ip(192, 168, 1, 177);
28+
29+
EthernetServer ethServer(502);
30+
31+
ModbusTCPServer modbusTCPServer;
32+
33+
const int ledPin = LED_BUILTIN;
34+
35+
//create an example struct of a modbus memory map
36+
struct mb_context{
37+
uint8_t coils[10];
38+
uint8_t inputStats[10];
39+
uint16_t inputRegs[10];
40+
uint16_t holdingRegs[10];
41+
};
42+
43+
mb_context myModbusMap;
44+
45+
void updateLED() {
46+
// read the current value of the coil
47+
48+
49+
if (myModbusMap.coils[0]) {
50+
// coil value set, turn LED on
51+
digitalWrite(ledPin, HIGH);
52+
} else {
53+
// coild value clear, turn LED off
54+
digitalWrite(ledPin, LOW);
55+
}
56+
}
57+
58+
void setup() {
59+
// You can use Ethernet.init(pin) to configure the CS pin
60+
//Ethernet.init(10); // Most Arduino shields
61+
//Ethernet.init(5); // MKR ETH shield
62+
//Ethernet.init(0); // Teensy 2.0
63+
//Ethernet.init(20); // Teensy++ 2.0
64+
//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
65+
//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet
66+
67+
// Open serial communications and wait for port to open:
68+
Serial.begin(9600);
69+
while (!Serial) {
70+
; // wait for serial port to connect. Needed for native USB port only
71+
}
72+
Serial.println("Ethernet Modbus TCP Example");
73+
74+
// start the Ethernet connection and the server:
75+
Ethernet.begin(mac, ip);
76+
77+
// Check for Ethernet hardware present
78+
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
79+
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
80+
while (true) {
81+
delay(1); // do nothing, no point running without Ethernet hardware
82+
}
83+
}
84+
if (Ethernet.linkStatus() == LinkOFF) {
85+
Serial.println("Ethernet cable is not connected.");
86+
}
87+
88+
// start the server
89+
ethServer.begin();
90+
91+
// start the Modbus TCP server
92+
if (!modbusTCPServer.begin()) {
93+
Serial.println("Failed to start Modbus TCP Server!");
94+
while (1);
95+
}
96+
97+
// configure the LED
98+
pinMode(ledPin, OUTPUT);
99+
digitalWrite(ledPin, LOW);
100+
101+
// configure a each modbus table's pointer and length
102+
modbusTCPServer.configureCoilPointer(myModbusMap.coils, 0x00, 10);
103+
modbusTCPServer.configureDiscreteInputPointer(myModbusMap.inputStats, 0x00, 10);
104+
modbusTCPServer.configureInputRegisterPointer(myModbusMap.inputRegs, 0x00, 10);
105+
modbusTCPServer.configureHoldingRegisterPointer(myModbusMap.holdingRegs, 0x00, 10);
106+
}
107+
108+
void loop() {
109+
// listen for incoming clients
110+
EthernetClient client = ethServer.available();
111+
112+
if (client) {
113+
// a new client connected
114+
Serial.println("new client");
115+
116+
// let the Modbus TCP accept the connection
117+
modbusTCPServer.accept(client);
118+
119+
while (client.connected()) {
120+
// poll for Modbus TCP requests, while client connected
121+
modbusTCPServer.poll();
122+
123+
// update the LED
124+
updateLED();
125+
}
126+
127+
Serial.println("client disconnected");
128+
}
129+
}

src/ModbusServer.cpp

+56
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,21 @@ ModbusServer::~ModbusServer()
5050
}
5151
}
5252

53+
int ModbusServer::configureCoilPointer(uint8_t *ptr, int startAddress, int nb)
54+
{
55+
if (startAddress < 0 || nb < 1) {
56+
errno = EINVAL;
57+
58+
return -1;
59+
}
60+
61+
_mbMapping.tab_bits = ptr;
62+
_mbMapping.start_bits = startAddress;
63+
_mbMapping.nb_bits = nb;
64+
65+
return 1;
66+
}
67+
5368
int ModbusServer::configureCoils(int startAddress, int nb)
5469
{
5570
if (startAddress < 0 || nb < 1) {
@@ -76,6 +91,20 @@ int ModbusServer::configureCoils(int startAddress, int nb)
7691
return 1;
7792
}
7893

94+
int ModbusServer::configureDiscreteInputPointer(uint8_t *ptr, int startAddress, int nb)
95+
{
96+
if (startAddress < 0 || nb < 1) {
97+
errno = EINVAL;
98+
99+
return -1;
100+
}
101+
_mbMapping.tab_input_bits = ptr;
102+
_mbMapping.start_input_bits = startAddress;
103+
_mbMapping.nb_input_bits = nb;
104+
105+
return 1;
106+
}
107+
79108
int ModbusServer::configureDiscreteInputs(int startAddress, int nb)
80109
{
81110
if (startAddress < 0 || nb < 1) {
@@ -102,6 +131,19 @@ int ModbusServer::configureDiscreteInputs(int startAddress, int nb)
102131
return 1;
103132
}
104133

134+
int ModbusServer::configureHoldingRegisterPointer(uint16_t *ptr, int startAddress, int nb)
135+
{
136+
if (startAddress < 0 || nb < 1) {
137+
errno = EINVAL;
138+
139+
return -1;
140+
}
141+
_mbMapping.tab_registers = ptr;
142+
_mbMapping.start_registers = startAddress;
143+
_mbMapping.nb_registers = nb;
144+
return 1;
145+
}
146+
105147
int ModbusServer::configureHoldingRegisters(int startAddress, int nb)
106148
{
107149
if (startAddress < 0 || nb < 1) {
@@ -128,6 +170,20 @@ int ModbusServer::configureHoldingRegisters(int startAddress, int nb)
128170
return 1;
129171
}
130172

173+
int ModbusServer::configureInputRegisterPointer(uint16_t *ptr, int startAddress, int nb)
174+
{
175+
if (startAddress < 0 || nb < 1) {
176+
errno = EINVAL;
177+
178+
return -1;
179+
}
180+
_mbMapping.tab_input_registers = ptr;
181+
_mbMapping.start_input_registers = startAddress;
182+
_mbMapping.nb_input_registers = nb;
183+
184+
return 1;
185+
}
186+
131187
int ModbusServer::configureInputRegisters(int startAddress, int nb)
132188
{
133189
if (startAddress < 0 || nb < 1) {

src/ModbusServer.h

+44
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ extern "C" {
2929
class ModbusServer {
3030

3131
public:
32+
/**
33+
* Configure the servers coil starting address.
34+
*
35+
* @param ptr pointer address of existing data struct
36+
* @param startAddress start address of holding registers
37+
* @param nb number of holding registers to configure
38+
*
39+
* @return 0 on success, 1 on failure
40+
*/
41+
int configureCoilPointer(uint8_t *ptr, int startAddress, int nb);
42+
3243
/**
3344
* Configure the servers coils.
3445
*
@@ -39,6 +50,17 @@ class ModbusServer {
3950
*/
4051
int configureCoils(int startAddress, int nb);
4152

53+
/**
54+
* Configure the servers discrete inputs starting address.
55+
*
56+
* @param ptr pointer address of existing data struct
57+
* @param startAddress start address of holding registers
58+
* @param nb number of holding registers to configure
59+
*
60+
* @return 0 on success, 1 on failure
61+
*/
62+
int configureDiscreteInputPointer(uint8_t *ptr, int startAddress, int nb);
63+
4264
/**
4365
* Configure the servers discrete inputs.
4466
*
@@ -49,6 +71,17 @@ class ModbusServer {
4971
*/
5072
int configureDiscreteInputs(int startAddress, int nb);
5173

74+
/**
75+
* Configure the servers holding registers starting address.
76+
*
77+
* @param ptr pointer address of existing data struct
78+
* @param startAddress start address of holding registers
79+
* @param nb number of holding registers to configure
80+
*
81+
* @return 0 on success, 1 on failure
82+
*/
83+
int configureHoldingRegisterPointer(uint16_t *ptr, int startAddress, int nb);
84+
5285
/**
5386
* Configure the servers holding registers.
5487
*
@@ -59,6 +92,17 @@ class ModbusServer {
5992
*/
6093
int configureHoldingRegisters(int startAddress, int nb);
6194

95+
/**
96+
* Configure the servers input registers starting address.
97+
*
98+
* @param ptr pointer address of existing data struct
99+
* @param startAddress start address of holding registers
100+
* @param nb number of holding registers to configure
101+
*
102+
* @return 0 on success, 1 on failure
103+
*/
104+
int configureInputRegisterPointer(uint16_t *ptr, int startAddress, int nb);
105+
62106
/**
63107
* Configure the servers input registers.
64108
*

0 commit comments

Comments
 (0)