From 7997cf998c6074be6fa9959333dc1a83e37b562b Mon Sep 17 00:00:00 2001 From: Adam Solchenberger Date: Fri, 8 Oct 2021 13:59:00 -0500 Subject: [PATCH] added methods to configure modbus server to existing data stuctures --- .../EthernetModbusServerPointerMapping.ino | 129 ++++++++++++++++++ src/ModbusServer.cpp | 56 ++++++++ src/ModbusServer.h | 44 ++++++ 3 files changed, 229 insertions(+) create mode 100644 examples/TCP/EthernetModbusServerPointerMapping/EthernetModbusServerPointerMapping.ino diff --git a/examples/TCP/EthernetModbusServerPointerMapping/EthernetModbusServerPointerMapping.ino b/examples/TCP/EthernetModbusServerPointerMapping/EthernetModbusServerPointerMapping.ino new file mode 100644 index 0000000..af715a2 --- /dev/null +++ b/examples/TCP/EthernetModbusServerPointerMapping/EthernetModbusServerPointerMapping.ino @@ -0,0 +1,129 @@ +/* + Ethernet Modbus TCP Server LED using existing variables as modbus memory + + This sketch creates a Modbus TCP Server with a simulated coil. + The value of the simulated coil is set on the LED + + Circuit: + - Any Arduino MKR Board + - MKR ETH Shield + + created 16 July 2018 + by Sandeep Mistry +*/ + +#include +#include + +#include // ArduinoModbus depends on the ArduinoRS485 library +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +// The IP address will be dependent on your local network: +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; +IPAddress ip(192, 168, 1, 177); + +EthernetServer ethServer(502); + +ModbusTCPServer modbusTCPServer; + +const int ledPin = LED_BUILTIN; + +//create an example struct of a modbus memory map +struct mb_context{ + uint8_t coils[10]; + uint8_t inputStats[10]; + uint16_t inputRegs[10]; + uint16_t holdingRegs[10]; +}; + +mb_context myModbusMap; + +void updateLED() { + // read the current value of the coil + + + if (myModbusMap.coils[0]) { + // coil value set, turn LED on + digitalWrite(ledPin, HIGH); + } else { + // coild value clear, turn LED off + digitalWrite(ledPin, LOW); + } +} + +void setup() { + // You can use Ethernet.init(pin) to configure the CS pin + //Ethernet.init(10); // Most Arduino shields + //Ethernet.init(5); // MKR ETH shield + //Ethernet.init(0); // Teensy 2.0 + //Ethernet.init(20); // Teensy++ 2.0 + //Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet + //Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet + + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + Serial.println("Ethernet Modbus TCP Example"); + + // start the Ethernet connection and the server: + Ethernet.begin(mac, ip); + + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + + // start the server + ethServer.begin(); + + // start the Modbus TCP server + if (!modbusTCPServer.begin()) { + Serial.println("Failed to start Modbus TCP Server!"); + while (1); + } + + // configure the LED + pinMode(ledPin, OUTPUT); + digitalWrite(ledPin, LOW); + + // configure a each modbus table's pointer and length + modbusTCPServer.configureCoilPointer(myModbusMap.coils, 0x00, 10); + modbusTCPServer.configureDiscreteInputPointer(myModbusMap.inputStats, 0x00, 10); + modbusTCPServer.configureInputRegisterPointer(myModbusMap.inputRegs, 0x00, 10); + modbusTCPServer.configureHoldingRegisterPointer(myModbusMap.holdingRegs, 0x00, 10); +} + +void loop() { + // listen for incoming clients + EthernetClient client = ethServer.available(); + + if (client) { + // a new client connected + Serial.println("new client"); + + // let the Modbus TCP accept the connection + modbusTCPServer.accept(client); + + while (client.connected()) { + // poll for Modbus TCP requests, while client connected + modbusTCPServer.poll(); + + // update the LED + updateLED(); + } + + Serial.println("client disconnected"); + } +} \ No newline at end of file diff --git a/src/ModbusServer.cpp b/src/ModbusServer.cpp index 883f746..8bf9055 100644 --- a/src/ModbusServer.cpp +++ b/src/ModbusServer.cpp @@ -50,6 +50,21 @@ ModbusServer::~ModbusServer() } } +int ModbusServer::configureCoilPointer(uint8_t *ptr, int startAddress, int nb) +{ + if (startAddress < 0 || nb < 1) { + errno = EINVAL; + + return -1; + } + + _mbMapping.tab_bits = ptr; + _mbMapping.start_bits = startAddress; + _mbMapping.nb_bits = nb; + + return 1; +} + int ModbusServer::configureCoils(int startAddress, int nb) { if (startAddress < 0 || nb < 1) { @@ -76,6 +91,20 @@ int ModbusServer::configureCoils(int startAddress, int nb) return 1; } +int ModbusServer::configureDiscreteInputPointer(uint8_t *ptr, int startAddress, int nb) +{ + if (startAddress < 0 || nb < 1) { + errno = EINVAL; + + return -1; + } + _mbMapping.tab_input_bits = ptr; + _mbMapping.start_input_bits = startAddress; + _mbMapping.nb_input_bits = nb; + + return 1; +} + int ModbusServer::configureDiscreteInputs(int startAddress, int nb) { if (startAddress < 0 || nb < 1) { @@ -102,6 +131,19 @@ int ModbusServer::configureDiscreteInputs(int startAddress, int nb) return 1; } +int ModbusServer::configureHoldingRegisterPointer(uint16_t *ptr, int startAddress, int nb) + { + if (startAddress < 0 || nb < 1) { + errno = EINVAL; + + return -1; + } + _mbMapping.tab_registers = ptr; + _mbMapping.start_registers = startAddress; + _mbMapping.nb_registers = nb; + return 1; +} + int ModbusServer::configureHoldingRegisters(int startAddress, int nb) { if (startAddress < 0 || nb < 1) { @@ -128,6 +170,20 @@ int ModbusServer::configureHoldingRegisters(int startAddress, int nb) return 1; } +int ModbusServer::configureInputRegisterPointer(uint16_t *ptr, int startAddress, int nb) + { + if (startAddress < 0 || nb < 1) { + errno = EINVAL; + + return -1; + } + _mbMapping.tab_input_registers = ptr; + _mbMapping.start_input_registers = startAddress; + _mbMapping.nb_input_registers = nb; + + return 1; +} + int ModbusServer::configureInputRegisters(int startAddress, int nb) { if (startAddress < 0 || nb < 1) { diff --git a/src/ModbusServer.h b/src/ModbusServer.h index 76fa7e3..0fea863 100644 --- a/src/ModbusServer.h +++ b/src/ModbusServer.h @@ -29,6 +29,17 @@ extern "C" { class ModbusServer { public: + /** + * Configure the servers coil starting address. + * + * @param ptr pointer address of existing data struct + * @param startAddress start address of holding registers + * @param nb number of holding registers to configure + * + * @return 0 on success, 1 on failure + */ + int configureCoilPointer(uint8_t *ptr, int startAddress, int nb); + /** * Configure the servers coils. * @@ -39,6 +50,17 @@ class ModbusServer { */ int configureCoils(int startAddress, int nb); + /** + * Configure the servers discrete inputs starting address. + * + * @param ptr pointer address of existing data struct + * @param startAddress start address of holding registers + * @param nb number of holding registers to configure + * + * @return 0 on success, 1 on failure + */ + int configureDiscreteInputPointer(uint8_t *ptr, int startAddress, int nb); + /** * Configure the servers discrete inputs. * @@ -49,6 +71,17 @@ class ModbusServer { */ int configureDiscreteInputs(int startAddress, int nb); + /** + * Configure the servers holding registers starting address. + * + * @param ptr pointer address of existing data struct + * @param startAddress start address of holding registers + * @param nb number of holding registers to configure + * + * @return 0 on success, 1 on failure + */ + int configureHoldingRegisterPointer(uint16_t *ptr, int startAddress, int nb); + /** * Configure the servers holding registers. * @@ -59,6 +92,17 @@ class ModbusServer { */ int configureHoldingRegisters(int startAddress, int nb); + /** + * Configure the servers input registers starting address. + * + * @param ptr pointer address of existing data struct + * @param startAddress start address of holding registers + * @param nb number of holding registers to configure + * + * @return 0 on success, 1 on failure + */ + int configureInputRegisterPointer(uint16_t *ptr, int startAddress, int nb); + /** * Configure the servers input registers. *