diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..97a2aa2
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,5 @@
+PROJECT_NAME = MODBUSino
+INPUT = modbusino.c modbusino.h
+OUTPUT_DIRECTORY = doxygen
+OPTIMIZE_OUTPUT_FOR_C = YES
+GENERATE_LATEX = NO
diff --git a/README.md b/README.md
index 14b30fa..8d26f22 100644
--- a/README.md
+++ b/README.md
@@ -148,3 +148,5 @@ make
## API reference
API reference is available in the repository [wiki]()
+
+
diff --git a/modbusino.h b/modbusino.h
index 10e8316..4c6e342 100644
--- a/modbusino.h
+++ b/modbusino.h
@@ -1,3 +1,15 @@
+/** @file */
+
+/*! \mainpage MODBUSino - A compact MODBUS RTU/TCP C library for microcontrollers
+ * MODBUSino is a small C library that implements the Modbus protocol. It is especially useful in resource-constrained
+ * system like microcontrollers.
+ *
+ * GtiHub: https://github.com/debevv/MODBUSino
+ *
+ * API reference: \link modbusino.h \endlink
+ *
+ */
+
#ifndef MODBUSINO_H
#define MODBUSINO_H
@@ -5,49 +17,92 @@
#include
#include
-
+/**
+ * MODBUSino errors.
+ * Values <= 0 are library errors, > 0 are modbus exceptions.
+ */
typedef enum mbsn_error {
// Library errors
- MBSN_ERROR_TRANSPORT = -4,
- MBSN_ERROR_TIMEOUT = -3,
- MBSN_ERROR_INVALID_RESPONSE = -2,
- MBSN_ERROR_INVALID_ARGUMENT = -1,
- MBSN_ERROR_NONE = 0,
+ MBSN_ERROR_TRANSPORT = -4, /**< Transport error */
+ MBSN_ERROR_TIMEOUT = -3, /**< Read/write timeout occurred */
+ MBSN_ERROR_INVALID_RESPONSE = -2, /**< Received invalid response from server */
+ MBSN_ERROR_INVALID_ARGUMENT = -1, /**< Invalid argument provided */
+ MBSN_ERROR_NONE = 0, /**< No error */
// Modbus exceptions
- MBSN_EXCEPTION_ILLEGAL_FUNCTION = 1,
- MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS = 2,
- MBSN_EXCEPTION_ILLEGAL_DATA_VALUE = 3,
- MBSN_EXCEPTION_SERVER_DEVICE_FAILURE = 4,
+ MBSN_EXCEPTION_ILLEGAL_FUNCTION = 1, /**< Modbus exception 1 */
+ MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS = 2, /**< Modbus exception 2 */
+ MBSN_EXCEPTION_ILLEGAL_DATA_VALUE = 3, /**< Modbus exception 3 */
+ MBSN_EXCEPTION_SERVER_DEVICE_FAILURE = 4, /**< Modbus exception 4 */
} mbsn_error;
+/**
+ * Return whether the mbsn_error is a modbus exception
+ * @e mbsn_error to check
+ */
#define mbsn_error_is_exception(e) ((e) > 0 && (e) < 5)
+/**
+ * Bitfield consisting of 2000 coils/discrete inputs
+ */
typedef uint8_t mbsn_bitfield[250];
+/**
+ * Read a bit from the mbsn_bitfield bf at position b
+ */
#define mbsn_bitfield_read(bf, b) ((bool) ((bf)[(b) / 8] & (0x1 << ((b) % 8))))
+/**
+ * Write value v to the mbsn_bitfield bf at position b
+ */
#define mbsn_bitfield_write(bf, b, v) \
(((bf)[(b) / 8]) = ((v) ? (((bf)[(b) / 8]) | (0x1 << ((b) % 8))) : (((bf)[(b) / 8]) & ~(0x1 << ((b) % 8)))))
+/**
+ * Reset (zero) the whole bitfield
+ */
#define mbsn_bitfield_reset(bf) memset(bf, 0, sizeof(mbsn_bitfield))
+/**
+ * Modbus transport type.
+ */
typedef enum mbsn_transport {
MBSN_TRANSPORT_RTU = 1,
MBSN_TRANSPORT_TCP = 2,
} mbsn_transport;
+
+/**
+ * MODBUSino platform configuration struct.
+ * Passed to mbsn_server_create() and mbsn_client_create().
+ *
+ * read_byte() and write_byte() are the platform-specific methods that read/write data to/from a serial port or a TCP connection.
+ * Both methods should block until the requested byte is read/written.
+ * If your implementation uses a read/write timeout, and the timeout expires, the methods should return 0.
+ * Their return values should be:
+ * - `1` in case of success
+ * - `0` if no data is available immediately or after an internal timeout expiration
+ * - `-1` in case of error
+ *
+ * sleep() is the platform-specific method to pause for a certain amount of milliseconds.
+ *
+ * These methods accept a pointer to arbitrary user-data, which is the arg member of this struct.
+ * After the creation of an instance it can be changed with mbsn_set_platform_arg().
+ */
typedef struct mbsn_platform_conf {
- mbsn_transport transport;
- int (*read_byte)(uint8_t* b, int32_t, void* arg);
- int (*write_byte)(uint8_t b, int32_t, void* arg);
- void (*sleep)(uint32_t milliseconds, void* arg);
- void* arg;
+ mbsn_transport transport; /*!< Transport type */
+ int (*read_byte)(uint8_t* b, int32_t, void* arg); /*!< Byte read transport function pointer */
+ int (*write_byte)(uint8_t b, int32_t, void* arg); /*!< Byte write transport function pointer */
+ void (*sleep)(uint32_t milliseconds, void* arg); /*!< Sleep function pointer */
+ void* arg; /*!< User data, will be passed to functions above */
} mbsn_platform_conf;
+/**
+ * Modbus server request callbacks. Passed to mbsn_server_create().
+ */
typedef struct mbsn_callbacks {
mbsn_error (*read_coils)(uint16_t address, uint16_t quantity, mbsn_bitfield coils_out);
mbsn_error (*read_discrete_inputs)(uint16_t address, uint16_t quantity, mbsn_bitfield inputs_out);
@@ -60,6 +115,9 @@ typedef struct mbsn_callbacks {
} mbsn_callbacks;
+/**
+ * MODBUSino client/server instance type. All struct members are to be considered private, it is not advisable to read/write them directly.
+ */
typedef struct mbsn_t {
struct {
uint8_t buf[260];
@@ -85,48 +143,176 @@ typedef struct mbsn_t {
uint16_t current_tid;
} mbsn_t;
-
+/**
+ * Modbus broadcast address. Can be passed to mbsn_set_destination_rtu_address().
+ */
static const uint8_t MBSN_BROADCAST_ADDRESS = 0;
+/** Create a new Modbus client.
+ * @param mbsn pointer to the mbsn_t instance where the client will be created.
+ * @param platform_conf mbsn_platform_conf struct with platform configuration.
+ *
+* @return MBSN_ERROR_NONE if successful, MBSN_ERROR_INVALID_ARGUMENT otherwise.
+ */
mbsn_error mbsn_client_create(mbsn_t* mbsn, const mbsn_platform_conf* platform_conf);
+/** Create a new Modbus server.
+ * @param mbsn pointer to the mbsn_t instance where the client will be created.
+ * @param address_rtu RTU address of this server. Can be 0 if transport is not RTU.
+ * @param platform_conf mbsn_platform_conf struct with platform configuration.
+ * @param callbacks mbsn_callbacks struct with server request callbacks.
+ *
+ * @return MBSN_ERROR_NONE if successful, MBSN_ERROR_INVALID_ARGUMENT otherwise.
+ */
mbsn_error mbsn_server_create(mbsn_t* mbsn, uint8_t address_rtu, const mbsn_platform_conf* platform_conf,
const mbsn_callbacks* callbacks);
+/** Set the request/response timeout.
+ * If the target instance is a server, sets the timeout of the mbsn_server_poll() function.
+ * If the target instance is a client, sets the response timeout after sending a request. In case of timeout, the called method will return MBSN_ERROR_TIMEOUT.
+ * @param mbsn pointer to the mbsn_t instance
+ * @param timeout_ms timeout in milliseconds. If < 0, the timeout is disabled.
+ */
void mbsn_set_read_timeout(mbsn_t* mbsn, int32_t timeout_ms);
+/** Set the timeout between the reception of two consecutive bytes.
+ * @param mbsn pointer to the mbsn_t instance
+ * @param timeout_ms timeout in milliseconds. If < 0, the timeout is disabled.
+ */
void mbsn_set_byte_timeout(mbsn_t* mbsn, int32_t timeout_ms);
+/** Set the spacing between two sent bytes. This value is ignored when transport is not RTU.
+ * @param mbsn pointer to the mbsn_t instance
+ * @param timeout_ms time spacing in milliseconds.
+ */
void mbsn_set_byte_spacing(mbsn_t* mbsn, uint32_t spacing_ms);
+/** Set the pointer to user data argument passed to platform functions.
+ * @param mbsn pointer to the mbsn_t instance
+ * @param arg user data argument
+ */
void mbsn_set_platform_arg(mbsn_t* mbsn, void* arg);
+/** Set the recipient server address of the next request on RTU transport.
+ * @param mbsn pointer to the mbsn_t instance
+ * @param address server address
+ */
void mbsn_set_destination_rtu_address(mbsn_t* mbsn, uint8_t address);
+/** Handle incoming requests to the server.
+ * This function should be called in a loop in order to serve any incoming request. Its maximum duration, in case of no
+ * received request, is the value set with mbsn_set_read_timeout() (unless set to < 0).
+ * @param mbsn pointer to the mbsn_t instance
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_server_poll(mbsn_t* mbsn);
+/** Send a FC 01 (0x01) Read Coils request
+ * @param mbsn pointer to the mbsn_t instance
+ * @param address starting address
+ * @param quantity quantity of coils
+ * @param coils_out mbsn_bitfield where the coils will be stored
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_read_coils(mbsn_t* mbsn, uint16_t address, uint16_t quantity, mbsn_bitfield coils_out);
+/** Send a FC 02 (0x02) Read Discrete Inputs request
+ * @param mbsn pointer to the mbsn_t instance
+ * @param address starting address
+ * @param quantity quantity of inputs
+ * @param inputs_out mbsn_bitfield where the discrete inputs will be stored
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_read_discrete_inputs(mbsn_t* mbsn, uint16_t address, uint16_t quantity, mbsn_bitfield inputs_out);
+/** Send a FC 03 (0x03) Read Holding Registers request
+ * @param mbsn pointer to the mbsn_t instance
+ * @param address starting address
+ * @param quantity quantity of registers
+ * @param registers_out array where the registers will be stored
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_read_holding_registers(mbsn_t* mbsn, uint16_t address, uint16_t quantity, uint16_t* registers_out);
+/** Send a FC 04 (0x04) Read Input Registers request
+ * @param mbsn pointer to the mbsn_t instance
+ * @param address starting address
+ * @param quantity quantity of registers
+ * @param registers_out array where the registers will be stored
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_read_input_registers(mbsn_t* mbsn, uint16_t address, uint16_t quantity, uint16_t* registers_out);
+/** Send a FC 05 (0x05) Write Single Coil request
+ * @param mbsn pointer to the mbsn_t instance
+ * @param address coil address
+ * @param value coil value
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_write_single_coil(mbsn_t* mbsn, uint16_t address, bool value);
+/** Send a FC 06 (0x06) Write Single Register request
+ * @param mbsn pointer to the mbsn_t instance
+ * @param address register address
+ * @param value register value
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_write_single_register(mbsn_t* mbsn, uint16_t address, uint16_t value);
+/** Send a FC 15 (0x0F) Write Multiple Coils
+ * @param mbsn pointer to the mbsn_t instance
+ * @param address starting address
+ * @param quantity quantity of coils
+ * @param coils bitfield of coils values
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_write_multiple_coils(mbsn_t* mbsn, uint16_t address, uint16_t quantity, const mbsn_bitfield coils);
+/** Send a FC 16 (0x10) Write Multiple Registers
+ * @param mbsn pointer to the mbsn_t instance
+ * @param address starting address
+ * @param quantity quantity of registers
+ * @param registers array of registers values
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_write_multiple_registers(mbsn_t* mbsn, uint16_t address, uint16_t quantity, const uint16_t* registers);
+/** Send a raw Modbus PDU.
+ * CRC on RTU will be calculated and sent by this function.
+ * @param mbsn pointer to the mbsn_t instance
+ * @param fc request function code
+ * @param data request data. It's up to the caller to convert this data to network byte order
+ * @param data_len length of the data parameter
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_send_raw_pdu(mbsn_t* mbsn, uint8_t fc, const void* data, uint32_t data_len);
+/** Receive a raw response Modbus PDU.
+ * @param mbsn pointer to the mbsn_t instance
+ * @param data_out response data. It's up to the caller to convert this data to host byte order.
+ * @param data_out_len length of the data_out parameter
+ *
+ * @return MBSN_ERROR_NONE if successful, other errors otherwise.
+ */
mbsn_error mbsn_receive_raw_pdu_response(mbsn_t* mbsn, void* data_out, uint32_t data_out_len);
#ifndef MBSN_STRERROR_DISABLED
+/** Convert a mbsn_error to string
+ * @param error error to be converted
+ *
+ * @return string representation of the error
+ */
const char* mbsn_strerror(mbsn_error error);
#endif