MODBUS Slave


Detailed Description

 #include "mbs.h" 

The API documentation is splitted into different parts. A typical application will only to have use the API function shown in this module. The most important functions are the functions for opening and closing a MODBUS slave instances. There are different function depending on the type of transmission you are going to use. For serial transmission modes the function eMBSSerialInit should be used. For MODBUS/TCP the function eMBSTCPInit should be used.


Modules

 MODBUS Configuration

Typedefs

typedef void * xMBSHandle
typedef eMBException(* peMBSCoilCB )(UBYTE *pubRegBuffer, USHORT usAddress, USHORT usNRegs, eMBSRegisterMode eRegMode) MB_CDECL_SUFFIX
typedef eMBException(* peMBSDiscreteInputCB )(UBYTE *pubRegBuffer, USHORT usAddress, USHORT usNRegs) MB_CDECL_SUFFIX
typedef eMBException(* peMBSRegisterInputCB )(UBYTE *pubRegBuffer, USHORT usAddress, USHORT usNRegs) MB_CDECL_SUFFIX
typedef eMBException(* peMBSRegisterHoldingCB )(UBYTE *pubRegBuffer, USHORT usAddress, USHORT usNRegs, eMBSRegisterMode eRegMode) MB_CDECL_SUFFIX
typedef eMBException(* peMBSGatewayCB )(UBYTE ubSlaveAddress, UBYTE *pubMBPDU, USHORT *pusMBPDULength) MB_CDECL_SUFFIX
typedef eMBException(* peMBSSerialDiagCB )(eMBSSerialDiagQueryType_t eQueryType, UBYTE *pubMBPDU, USHORT *pusMBPDULength, const USHORT usMBPDULengthMax) MB_CDECL_SUFFIX

Enumerations

enum  eMBSRegisterMode { MBS_REGISTER_WRITE, MBS_REGISTER_READ }
enum  eMBSSerialDiagQueryType_t {
  DEVICE_IDENTIFICATION_OBJECT_ID_VENDORNAME = 0x00, DEVICE_IDENTIFICATION_OBJECT_ID_PRODUCTCODE = 0x01, DEVICE_IDENTIFICATION_OBJECT_ID_MAJORMINORREVISION = 0x02, DEVICE_IDENTIFICATION_OBJECT_ID_VENDORURL = 0x03,
  DEVICE_IDENTIFICATION_OBJECT_ID_PRODUCTNAME = 0x04, DEVICE_IDENTIFICATION_OBJECT_ID_MODELNAME = 0x05, DEVICE_IDENTIFICATION_OBJECT_ID_USERAPPLICATIONNAME = 0x06, DEVICE_IDENTIFICATION_OBJECT_ID_USER_START = 0x80,
  DEVICE_IDENTIFICATION_OBJECT_ID_USER_END = 0xFF, REPORT_SLAVE_ID_REQUEST_SLAVE_ID = 0x1000, REPORT_SLAVE_ID_REQUEST_STATUS = 0x1001, REPORT_SLAVE_ID_REQUEST_ADDITIONAL_DATA = 0x1002
}

Functions

eMBErrorCode eMBSGetRequestSlaveAddress (xMBSHandle xHdl, UBYTE *pubAddress)
eMBErrorCode eMBSGetStatistics (xMBSHandle xHdl, xMBStat *pxMBSCurrentStat)
eMBErrorCode eMBSResetStatistics (xMBSHandle xHdl)
eMBErrorCode eMBSRegisterProtAnalyzer (xMBSHandle xHdl, void *pvCtxArg, pvMBAnalyzerCallbackCB pvMBAnalyzerCallbackFN)
eMBErrorCode eMBSRegisterFunctionCB (xMBSHandle xHdl, UBYTE ubFuncIdx, peMBSCustomFunctionCB peFuncCB)
eMBErrorCode eMBSRegisterCoilCB (xMBSHandle xHdl, peMBSCoilCB peMBSCoilsCB)
eMBErrorCode eMBSRegisterDiscreteCB (xMBSHandle xHdl, peMBSDiscreteInputCB peDiscInputCB)
eMBErrorCode eMBSRegisterInputCB (xMBSHandle xHdl, peMBSRegisterInputCB peRegInputCB)
eMBErrorCode eMBSRegisterHoldingCB (xMBSHandle xHdl, peMBSRegisterHoldingCB peRegHoldingCB)
eMBErrorCode eMBSRegisterSerialDiagCB (xMBSHandle xHdl, peMBSSerialDiagCB peMBSSerDiagCB)
eMBErrorCode eMBSRegisterGatewayCB (xMBSHandle xHdl, peMBSGatewayCB peGatewayCB)
eMBErrorCode eMBSClose (xMBSHandle xHdl)
eMBErrorCode eMBSPoll (xMBSHandle xHdl)
eMBErrorCode eMBSSerialInit (xMBSHandle *pxHdl, eMBSerialMode eMode, UBYTE ubSlaveAddress, UBYTE ubPort, ULONG ulBaudRate, eMBSerialParity eParity)
eMBErrorCode eMBSSerialInitExt (xMBSHandle *pxHdl, eMBSerialMode eMode, UBYTE ubSlaveAddress, UBYTE ubPort, ULONG ulBaudRate, eMBSerialParity eParity, UCHAR ucStopBits)
eMBErrorCode eMBSTCPInit (xMBSHandle *pxHdl, CHAR *pcBindAddress, USHORT usTCPPort)
eMBErrorCode eMBSTCPSetGatewayMode (xMBSHandle xHdl, BOOL bEnable)


Typedef Documentation

typedef eMBException( * peMBSCoilCB)(UBYTE *pubRegBuffer, USHORT usAddress, USHORT usNRegs, eMBSRegisterMode eRegMode) MB_CDECL_SUFFIX
 

Callback function if a coil register is read or written by the protocol stack.

The callback may read or write up to 2000 coils where the first coil is address by the parameter usAddress. If the coils are read by the protocol stack the first coil should be written to the buffer pubRegBuffer where the first 8 coils should be written to pubRegBuffer[0], the second 8 coils to pubRegBuffer[1], ... If the total amount is not a multiple of 8 the missing coils should be set to zero.
If the coils are written by the protocol stack, which is indicated by the argument eRegMode set to eMBSRegisterMode::MBS_REGISTER_WRITE , then the callback should update its coils with the values supplied in pubRegBuffer. The enconding is the same as above.

Parameters:
pubRegBuffer If the values are read by the stack the callback should update the buffer. Otherwise the callback can read the new status of the coils from this buffer.
usAddress Address of first coil.
usNRegs Number of coils.
eRegMode If set to eMBSRegisterMode::MBS_REGISTER_READ the coils are read by the protocol stack. In case of eMBSRegisterMode::MBS_REGISTER_WRITE the protocol stack needs to know the current value of the coil register.
Returns:
If the callback returns eMBException::MB_PDU_EX_NONE a response is sent back to the master. Otherwise an appropriate exception frame is generated.

typedef eMBException( * peMBSDiscreteInputCB)(UBYTE *pubRegBuffer, USHORT usAddress, USHORT usNRegs) MB_CDECL_SUFFIX
 

Callback function if an discrete register is read by the protocol stack.

The callback may request up to 2000 discrete inputs where the first input to be returned is usAddress. The status of the discrete inputs should be written to the buffer pubRegBuffer where the first 8 registers should be written to pubRegBuffer[0], the second 8 registers to pubRegBuffer[1]. If the total amount is not a multiple of 8 missing values should be set to zero.

Parameters:
pubRegBuffer Buffer where the status of the registers should be written to.
usAddress First discrete input to be returned.
usNRegs Number of registers requested.
Returns:
If the callback returns eMBException::MB_PDU_EX_NONE a response is sent back to the master. Otherwise an appropriate exception frame is generated.

typedef eMBException( * peMBSGatewayCB)(UBYTE ubSlaveAddress, UBYTE *pubMBPDU, USHORT *pusMBPDULength) MB_CDECL_SUFFIX
 

Callback function for gateway mode.

The argument pubMBPDU contains the complete MODBUS protocol data unit.

Parameters:
ubSlaveAddress The slave address for which the request was intended.
pubMBPDU The MODBUS request sent by the MODBUS master which is pusMBPDULength bytes long. The response should be written into the same buffer and the length of the response should be written to pubMBPDULength. It must not exceed the size of 243 bytes.
pubMBPDULen Length of the MODBUS PDU.

typedef eMBException( * peMBSRegisterHoldingCB)(UBYTE *pubRegBuffer, USHORT usAddress, USHORT usNRegs, eMBSRegisterMode eRegMode) MB_CDECL_SUFFIX
 

Callback function if a holding register is read or written by the protocol stack.

If the MODBUS slave stack needs to now the value of holding registers it executes this callback with eRegisterMode = MBS_REGISTER_READ. The callback function should then store the current values of the registers starting at usAddress up to usAddress + usNRegs (not including the last one) into the buffer pubRegBuffer. The 16 bit registers values must be stored in big endian format.
If the values should be updated the function is called with eRegisterMode set to MBS_REGISTER_WRITE. The register values are passed in the buffer pubRegBuffer and it is the applications responsibility to use these values. The first register is stored in pubRegBuffer[0] - pubRegBuffer[1] where the high byte comes first (big endian).

Parameters:
pubRegBuffer A pointer to an internal buffer. If registers are read then exactly 2 * usNRegs bytes must be written to this buffer. If registers are written the application can read up to 2 * usNRegs from this buffer.
usAddress The address of the first register which should be returned. Registers start at zero.
usNRegs The number of registers to read.
eRegMode If the registers are read or written.
Returns:
If the callback returns eMBException::MB_PDU_EX_NONE a response is sent back to the master. Otherwise an appropriate exception frame is generated.

typedef eMBException( * peMBSRegisterInputCB)(UBYTE *pubRegBuffer, USHORT usAddress, USHORT usNRegs) MB_CDECL_SUFFIX
 

Callback function if an input register is read by the protocol stack.

If the MODBUS slave stack needs to now the values of input registers this callback function must store the current value of the registers starting atusAddress to usAddress + usNRegs (not including the last one) into the buffer pubRegBuffer. The 16 bit registers values must be stored in big endian format.

Parameters:
pubRegBuffer A pointer to an internal buffer. Exactly 2 * usNRegs bytes must be written to this buffer.
usAddress The address of the first register which should be returned. Registers start at zero.
usNRegs The number of registers to read.
Returns:
If the callback returns eMBException::MB_PDU_EX_NONE a response is sent back to the master. Otherwise an appropriate exception frame is generated.

typedef eMBException( * peMBSSerialDiagCB)(eMBSSerialDiagQueryType_t eQueryType, UBYTE *pubMBPDU, USHORT *pusMBPDULength, const USHORT usMBPDULengthMax) MB_CDECL_SUFFIX
 

This function is used by the serial diagnosis function codes to request device specific information.

This function is used for the MODBUS requests

  • Report Slave ID
  • Read Device Identification

When ever an object is need the callback function is called. It should then store the request data in the buffer pointed to by pubMBPDU. The number of bytes stored should be stored in pusMBPDULength. The function is not allowed to write more than usMBPDULengthMax bytes.

Parameters:
eQueryType Type of object requested.
pubMBPDU Buffer where object should be stored. If called with NULL the function should only check if it has an object for this type and return MB_PDU_EX_NONE if it has and MB_PDU_EX_ILLEGAL_DATA_ADDRESS if not.
pusMBPDULength Bytes written to the buffer.
usMBPDULengthMax Maximum number of bytes which can be stored in this buffer.
Returns:
eMBException::MB_PDU_EX_NONE if request information was stored. eMBException::MB_PDU_EX_ILLEGAL_DATA_ADDRESS if no such object exists. eMBException::MB_PDU_EX_ILLEGAL_DATA_VALUE if usMBPDULengthMax is not large enough to hold the data.

typedef void* xMBSHandle
 

A handle to a MODBUS slave instance.

Examples:
AVR/demo.c.


Enumeration Type Documentation

enum eMBSRegisterMode
 

If a register is written or read by the stack.

Enumeration values:
MBS_REGISTER_WRITE  The application values should be updated from the values passed to the callback function.
MBS_REGISTER_READ  The application should store the current register values into the buffer passed to the callback function.
Examples:
AVR/demo.c.

enum eMBSSerialDiagQueryType_t
 

Objects used in the peMBSSerialDiagCB callbacks.

These codes are used to identifiy different objects used for the report slave id and device identificiation calls.


Function Documentation

eMBErrorCode eMBSClose xMBSHandle  xHdl  ) 
 

Close the stack.

Shutdown the slave stack. This function waits until all pending MODBUS requests have been answered and then operation is stop. All resources are returned to the porting layer.

Parameters:
xHdl A handle for a MODBUS slave instances.
Returns:
eMBErrorCode::MB_ENOERR if the stack has been shut down.
Examples:
AVR/demo.c.

eMBErrorCode eMBSGetRequestSlaveAddress xMBSHandle  xHdl,
UBYTE pubAddress
 

Retrieve the current slave address for this request.

This function can only be called during a register callback. It then returns the slave address for this request in pubAddress.

Parameters:
xHdl A valid MODBUS slave handle.
pubAddress On return slave address is stored in this variable.
Returns:
eMBErrorCode::MB_EINVAL if called not within a callback. Otherwise eMBErrorCode::MB_ENOERR;

eMBErrorCode eMBSGetStatistics xMBSHandle  xHdl,
xMBStat pxMBSCurrentStat
 

Retrieve the current slave statistics.

This function populates the argument pxMBSCurrentStat with the current internal counters.

Parameters:
xHdl A valid MODBUS slave handle.
pxMBSCurrentStat A pointer to an (potentially unitialized) xMBStat datastructure. When the return value is eMBErrorCode::MB_ENOERR this data structure holds a copy of the internal counters.
Returns:
eMBErrorCode::MB_ENOERR if successful. In case of an invalid argument the function returns eMBErrorCode::MB_EINVAL.

eMBErrorCode eMBSPoll xMBSHandle  xHdl  ) 
 

The main polling loop of the MODBUS stack.

This function must be called periodically. The timer interval required is given by the application but a good starting point is somewhere around 50ms. Internally the function checks if any events have happened and if yes processes them.

Note:
Most customers do not need to implement the handling of eMBErrorCode::MB_EILLSTATE. But for example if a PPP connection which might break is used a possible fallback would shut down the stack, reopen the connection and then start the stack again.
Parameters:
xHdl The handle to poll.
Returns:
If the handle is not valid the function returns eMBErrorCode::MB_EINVAL. If an internal error occurred in the porting layer the function returns eMBErrorCode::MB_EILLSTATE and this protocol instance should be closed. Otherwise the function returns eMBErrorCode::MB_ENOERR.
Examples:
AVR/demo.c.

eMBErrorCode eMBSRegisterCoilCB xMBSHandle  xHdl,
peMBSCoilCB  peMBSCoilsCB
 

Register a function callback for coils.

Parameters:
xHdl A handle to a MODBUS slave instance.
peMBSCoilsCB A pointer to a function. This function is called whenever a coil is read or written. Use NULL to remove the previous callback.
Returns:
eMBErrorCode::MB_ENOERR if the input callback has been set or removed. eMBErrorCode::MB_EINVAL if the handle is not valid.

eMBErrorCode eMBSRegisterDiscreteCB xMBSHandle  xHdl,
peMBSDiscreteInputCB  peDiscInputCB
 

Register a function callback for discrete inputs.

Parameters:
xHdl A handle to a MODBUS slave instance.
peDiscInputCB A pointer to a function. This function is called whenever a discrete register is read. Use NULL to remove the previous callback.
Returns:
eMBErrorCode::MB_ENOERR if the input callback has been set or removed. eMBErrorCode::MB_EINVAL if the handle is not valid.
Examples:
AVR/demo.c.

eMBErrorCode eMBSRegisterFunctionCB xMBSHandle  xHdl,
UBYTE  ubFuncIdx,
peMBSCustomFunctionCB  peFuncCB
 

Register a new custom function for MODBUS function code ubFuncIdx.

Note:
Custom registered functions have precedence over internal function handlers. Therefore it is possible to implement your own function for handling input, holding, discrete and coil registers.
Parameters:
xHdl A handle to a MODBUS slave instance.
ubFuncIdx MODBUS function code for which the handle should be registered.
peFuncCB A callback function which is called by the stack whenever such a function is processed. Use NULL to remove a previous callback.
Returns:
eMBErrorCode::MB_ENOERR if the function code has been registered or removed. eMBErrorCode::MB_EINVAL if the handle is invalid or the function code is not within the allowed range of 1 - 127.

eMBErrorCode eMBSRegisterGatewayCB xMBSHandle  xHdl,
peMBSGatewayCB  peGatewayCB
 

Register function callback for serial diagnosis functions.

Parameters:
xHdl A handle to a MODBUS slave instance.
peGatewayCB A pointer to a function. This function is called when the gateway mode is enabled and a new frame is received which has a different slave address than this stack instance. In TCP mode these are all slave addresses different from 0 and 255. In RTU mode these are all slave addresses different from the slave address set by eMBSSerialInit.
Returns:
eMBErrorCode::MB_ENOERR if the input callback has been set or removed. eMBErrorCode::MB_EINVAL if the handle is not valid.

eMBErrorCode eMBSRegisterHoldingCB xMBSHandle  xHdl,
peMBSRegisterHoldingCB  peRegHoldingCB
 

Register a function callback for holding registers.

Parameters:
xHdl A handle to a MODBUS slave instance.
peRegHoldingCB A pointer to a function. This function is called whenever the value of a holding register is written or read. Use NULL to remove a previous callback.
Returns:
eMBErrorCode::MB_ENOERR if the input callback has been set or removed. eMBErrorCode::MB_EINVAL if the handle is not valid.
Examples:
AVR/demo.c.

eMBErrorCode eMBSRegisterInputCB xMBSHandle  xHdl,
peMBSRegisterInputCB  peRegInputCB
 

Register a function callback for input registers.

Parameters:
xHdl A handle to a MODBUS slave instance.
peRegInputCB A pointer to a function. This function is called whenever the value of an input register is required. Use NULL to remove a previous callback.
Returns:
eMBErrorCode::MB_ENOERR if the input callback has been set or removed. eMBErrorCode::MB_EINVAL if the handle is not valid.
Examples:
AVR/demo.c.

eMBErrorCode eMBSRegisterProtAnalyzer xMBSHandle  xHdl,
void *  pvCtxArg,
pvMBAnalyzerCallbackCB  pvMBAnalyzerCallbackFN
 

Register an protocol analyzer.

If a protocol analyzer has been registered a callback is made whenever a frame has been sent or received.

Parameters:
xHdl A valid MODBUS slave handle.
pvMBAnalyzerCallbackFN A valid pointer to a callback handler or NULL if the analyzer should be removed.
pvCtxArg A user defined context. Can be NULL.
Returns:
eMBErrorCode::MB_ENOERR if the analyzer has been added or removed. eMBErrorCode::MB_EINVAL in case of an invalid MODBUS handle.

eMBErrorCode eMBSRegisterSerialDiagCB xMBSHandle  xHdl,
peMBSSerialDiagCB  peMBSSerDiagCB
 

Register function callback for gateway mode.

Parameters:
xHdl A handle to a MODBUS slave instance.
peMBSSerDiagCB A pointer to a function. This function is called when the stack requests some diagnosis information which can only be supplied by the application (For example vendor information for report slave id).
Returns:
eMBErrorCode::MB_ENOERR if the input callback has been set or removed. eMBErrorCode::MB_EINVAL if the handle is not valid.

eMBErrorCode eMBSResetStatistics xMBSHandle  xHdl  ) 
 

Clears the current statistic counters.

Parameters:
xHdl A valid MODBUS slave handle.
Returns:
eMBErrorCode::MB_ENOERR if successful. In case of an invalid argument the function returns eMBErrorCode::MB_EINVAL.

eMBErrorCode eMBSSerialInit xMBSHandle pxHdl,
eMBSerialMode  eMode,
UBYTE  ubSlaveAddress,
UBYTE  ubPort,
ULONG  ulBaudRate,
eMBSerialParity  eParity
 

Create a new instances for a serial MODBUS slave instance using either ASCII or RTU transmission mode.

Note that after the stack has been created function pointers for input, holding, coil and discrete registers have to be provided. They can be set by calling any of the functions:

  • eMBSRegisterHoldingCB
  • eMBSRegisterInputCB
  • eMBSRegisterDiscreteCB
  • eMBSRegisterCoilCB

Note:
In RTU mode 11 bits are used for each data byte. The coding system is 8bit binary.
  • 1 start bit.
  • 8 data bits with LSB sent first.
  • 1 bit for parity (Even, Odd)
  • 1 or 2 stop bits (Two stopbits if no parity is used).
In ASCII mode 10 bits are used. The coding system uses the hexadecimal ASCII characters 0-8 and A-F. One hexadecimal characters contains 4-bits of data.
  • 1 start bit
  • 7 data bits with LSB sent first.
  • 1 bit for parity (Even, Odd)
  • 1 or 2 stop bits (Two stopbits if no parity is used).

Parameters:
pxHdl A pointer to a MODBUS handle. If the function returns eMBErrorCode::MB_ENOERR the handle is updated to hold a new and valid slave handle. This handle should never be modified by the user.
eMode The serial transmission mode to use. Either MB_RTU or MB_ASCII.
ubSlaveAddress The slave address. Only frames sent to this address or to the broadcast address are handled. Valid slave addresses are in the range 1 - 247.
ubPort The serial port to use. The meaning of this value depends on the porting layer.
ulBaudRate The baudrate. For example 38400.
eParity The parity to use.
Returns:
eMBErrorCode::MB_ENOERR if a new SLAVE has been created. Otherwise one of the following error codes is returned.
Examples:
AVR/demo.c.

eMBErrorCode eMBSSerialInitExt xMBSHandle pxHdl,
eMBSerialMode  eMode,
UBYTE  ubSlaveAddress,
UBYTE  ubPort,
ULONG  ulBaudRate,
eMBSerialParity  eParity,
UCHAR  ucStopBits
 

Create a new instances for a serial MODBUS slave instance using either ASCII or RTU transmission mode.

Parameters:
pxHdl A pointer to a MODBUS handle. If the function returns eMBErrorCode::MB_ENOERR the handle is updated to hold a new and valid slave handle. This handle should never be modified by the user.
eMode The serial transmission mode to use. Either MB_RTU or MB_ASCII.
ubSlaveAddress The slave address. Only frames sent to this address or to the broadcast address are handled. Valid slave addresses are in the range 1 - 247.
ubPort The serial port to use. The meaning of this value depends on the porting layer.
ulBaudRate The baudrate. For example 38400.
ucStopBits Number of stop bits to use.
eParity The parity to use.
Returns:
eMBErrorCode::MB_ENOERR if a new SLAVE has been created. Otherwise one of the following error codes is returned.

eMBErrorCode eMBSTCPInit xMBSHandle pxHdl,
CHAR pcBindAddress,
USHORT  usTCPPort
 

Create a new MODBUS TCP slave instance.

This function tries to create a new MODBUS TCP slave listening on the address pcBindAddress and on port usTCPPort.

Parameters:
pxHdl A pointer to a handle. On return this handle is updated to point to a valid internal handle. The handle should never be modified by the user.
pcBindAddress Address to bind to. For example "0.0.0.0".
usTCPPort The TCP port to bind to. Default port should be 502.
Returns:
eMBErrorCode::MB_ENOERR if a new SLAVE has been created. Otherwise one of the following error codes is returned.

eMBErrorCode eMBSTCPSetGatewayMode xMBSHandle  xHdl,
BOOL  bEnable
 

Enable gateway mode where the MODBUS TCP slave answers on all addresses.

Addresses 0 and 255 are MODBUS requests targeted to this slave. Other addresses from 1 - 247 should be forwarded to the appropriate clients.


(C) 2007 Embedded Solutions. Last updated on 23 Aug 2014.