MODBUS
https://en.wikipedia.org/wiki/Modbus
Implements MODBUS-RTU protocols.
Can use this directly, but generally preferable to create custom Device and Request classes. See R421A Relay Boards for an example.
Device properties include:
- Address
The address of a modbus slave. Modbus docs. call this the slave ID.
- Node
Represents something a slave device does. Modbus relay boards have one node for each output it controls.
- Node ID
The channel a node lives on. For the R421Axx relay boards this is the address or channel number. In a modbus transaction this is the address field.
For efficiency, nodes aren’t implemented as objects, just identifiers used by a Device / Controller. Nodes can be controlled using generic commands such as ‘open’, ‘close’, ‘toggle’, etc.
-
namespace IO::Modbus
Debug print support, outputs contents of packet
Enums
-
enum Exception
Modbus exception codes returned in response packets.
Values:
-
enumerator Success
No exception, transaction completed normally.
-
enumerator IllegalFunction
Function not allowed/supported/implemented, or device in wrong state to process request.
For example, an unconfigured device may be unable to return register values.
-
enumerator IllegalDataAddress
Data address not allowed.
More specifically, the combination of reference number and transfer length is invalid. For a controller with 100 registers, the ADU addresses the first register as 0, and the last one as 99.
If a request is submitted with a starting register address of 96 and a quantity of registers of 4, then this request will successfully operate (address-wise at least) on registers 96, 97, 98, 99.
If a request is submitted with a starting register address of 96 and a quantity of registers of 5, then this request will fail with Exception Code 0x02 “Illegal Data Address” since it attempts to operate on registers 96, 97, 98, 99 and 100, and there is no register with address 100.
-
enumerator IllegalDataValue
Data value not allowed.
This indicates a fault in the structure of the remainder of a complex request, such as that the implied length is incorrect. It specifically does NOT mean that a data item submitted for storage in a register has a value outside the expectation of the application program, since the MODBUS protocol is unaware of the significance of any particular value of any particular register.
-
enumerator SlaveDeviceFailure
Protocol slave device failure exception.
An unrecoverable error occurred while the server (or slave) was attempting to perform the requested action.
-
enumerator Success
Functions
-
ErrorCode readRequest(RS485::Controller &controller, ADU &adu)
-
void sendResponse(RS485::Controller &controller, ADU &adu)
-
struct ADU
- #include <ADU.h>
Prepare outgoing packet
The
slaveAddress
andpdu
fields must be correctly initialised.- returns size_t
Size of ADU, 0 on error
Parse a received packet
- param receivedSize
How much data was received
- returns ErrorCode
Result of parsing
-
class Device : public IO::RS485::Device
- #include <Device.h>
A virtual device, represents a modbus slave device.
Actual devices must implement:
createRequest()
callback()
fillRequestData()
Subclassed by IO::Modbus::R421A::Device
Public Functions
-
virtual void handleEvent(IO::Request *request, Event event) override
Implementations may override this method to customise event handling.
-
struct PDU
- #include <PDU.h>
Protocol Data Unit.
Content is independent of the communication layer. Structure does NOT represent over-the-wire format as packing issues make handling PDU::Data awkward. Therefore, the other fields are unaligned and adjusted as required when sent over the wire.
byteCount
fieldSome functions with a
byteCount
field are marked ascalculated
. This means it doesn’t need to be set when constructing requests or responses, and will be filled in later based on the values of other fields.In other cases, a
setCount
method is provided to help ensure the byteCount field is set correctly.Get PDU size based on content
Calculation uses byte count so doesn’t access any 16-bit fields
-
union Data
- #include <PDU.h>
Public Members
-
uint8_t exceptionCode
-
ReadDiscreteInputs readDiscreteInputs
-
ReadHoldingRegisters readHoldingRegisters
-
ReadInputRegisters readInputRegisters
-
WriteSingleCoil writeSingleCoil
-
WriteSingleRegister writeSingleRegister
-
ReadExceptionStatus readExceptionStatus
-
GetComEventCounter getComEventCounter
-
GetComEventLog getComEventLog
-
WriteMultipleCoils writeMultipleCoils
-
WriteMultipleRegisters writeMultipleRegisters
-
ReportServerId reportServerId
-
MaskWriteRegister maskWriteRegister
-
ReadWriteMultipleRegisters readWriteMultipleRegisters
-
union GetComEventLog
- #include <PDU.h>
-
union ReadCoils
- #include <PDU.h>
-
struct Request
- #include <PDU.h>
-
struct Response
- #include <PDU.h>
-
struct Request
-
union ReportServerId
- #include <PDU.h>
-
uint8_t exceptionCode
-
union Data
-
class Request : public IO::Request
- #include <Request.h>
Subclassed by IO::Modbus::R421A::Request
-
namespace R421A
-
class Device : public IO::Modbus::Device
- #include <Device.h>
Public Functions
-
virtual IO::Request *createRequest() override
Create a request object for this device.
- Returns
Request* – Caller must destroy or submit the request
-
inline virtual DevNode::ID nodeIdMin() const override
Get minimum valid Node ID for this device.
Typically devices have a contiguous valid range of node IDs
-
inline virtual DevNode::ID nodeIdMax() const override
Get maximum valid Node ID for this device.
-
inline virtual uint16_t maxNodes() const override
Determine maximum number of nodes supported by the devicce.
- Returns
uint16_t – 0 if device doesn’t support nodes
-
virtual DevNode::States getNodeStates(DevNode node) const override
Return the current set of states for all nodes controlled by this device.
Used to determine if, say, all nodes are ON, OFF or a combination.
-
virtual void handleEvent(IO::Request *request, Event event) override
Implementations may override this method to customise event handling.
-
class Factory : public IO::Device::Factory
- #include <Device.h>
Public Functions
-
inline virtual IO::Device *createDevice(IO::Controller &controller, const char *id) const override
Create a new device instance.
Called by
DeviceManager::createDevice()
- Parameters
controller – The owning controller
id – Unique identifier for the device
- Returns
Device* – The constructed instance
-
inline virtual const FlashString &controllerClass() const override
Return the expected controller type for this device class, e.g. ‘rs485’.
The Device Manager uses this value to verify that devices are constructed using the correct controller.
-
inline virtual const FlashString &deviceClass() const override
Return the Device class name, e.g. ‘r421a’.
-
inline virtual IO::Device *createDevice(IO::Controller &controller, const char *id) const override
-
virtual IO::Request *createRequest() override
-
class Request : public IO::Modbus::Request
- #include <Request.h>
Public Functions
-
virtual ErrorCode parseJson(JsonObjectConst json) override
Fill this request from a JSON description.
-
virtual void getJson(JsonObject json) const override
Get result of a completed request in JSON format.
-
virtual bool setNode(DevNode node) override
If nodes are supported, implemented this method.
-
virtual DevNode::States getNodeStates(DevNode node) override
Query node status from response.
-
virtual ErrorCode parseJson(JsonObjectConst json) override
-
class Device : public IO::Modbus::Device
-
enum Exception