From 5358abde7b79558e68f2c6d7d812efb55a8cd790 Mon Sep 17 00:00:00 2001 From: Valerio De Benedetto Date: Sun, 24 Apr 2022 13:53:40 +0200 Subject: [PATCH] Support to NMBS_CLIENT_DISABLED and NMBS_SERVER_DISABLED defines --- CMakeLists.txt | 5 ++-- README.md | 10 ++++--- nanomodbus.c | 60 ++++++++++++++++++++++++++++++++++++++--- nanomodbus.h | 29 +++++++++++++++++++- tests/client_disabled.c | 46 +++++++++++++++++++++++++++++++ tests/server_disabled.c | 44 ++++++++++++++++++++++++++++++ 6 files changed, 184 insertions(+), 10 deletions(-) create mode 100644 tests/client_disabled.c create mode 100644 tests/server_disabled.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d454529..6821a71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,10 @@ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3") include_directories(tests examples .) -#add_definitions(-DNMBS_DEBUG) - add_executable(nanomodbus_tests nanomodbus.c tests/nanomodbus_tests.c) +add_executable(server_disabled nanomodbus.c tests/server_disabled.c) +add_executable(client_disabled nanomodbus.c tests/client_disabled.c) + add_executable(client-tcp nanomodbus.c examples/client-tcp.c) add_executable(server-tcp nanomodbus.c examples/server-tcp.c) diff --git a/README.md b/README.md index b625b6f..d8ead80 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ nanoMODBUS is a small C library that implements the Modbus protocol. It is espec system like microcontrollers. Its main features are: -- Compact size, only ~1000 lines of code +- Compact size + - Only ~1000 lines of code + - Client and server code can be disabled, if not needed - No dynamic memory allocations - Transports: - RTU @@ -145,6 +147,8 @@ make ## Misc -- To reduce code size, you can define `NMBS_STRERROR_DISABLED` to disable the code that converts `nmbs_error`s to - strings +- To reduce code size, you can define the following `#define`s: + - `NMBS_CLIENT_DISABLED` to disable all client code + - `NMBS_SERVER_DISABLED` to disable all server code + - `NMBS_STRERROR_DISABLED` to disable the code that converts `nmbs_error`s to strings - Debug prints about received and sent messages can be enabled by defining `NMBS_DEBUG` diff --git a/nanomodbus.c b/nanomodbus.c index fe0a6c1..1c327b5 100644 --- a/nanomodbus.c +++ b/nanomodbus.c @@ -123,11 +123,13 @@ int nmbs_create(nmbs_t* nmbs, const nmbs_platform_conf* platform_conf) { } +#ifndef NMBS_CLIENT_DISABLED nmbs_error nmbs_client_create(nmbs_t* nmbs, const nmbs_platform_conf* platform_conf) { return nmbs_create(nmbs, platform_conf); } +#endif - +#ifndef NMBS_SERVER_DISABLED nmbs_error nmbs_server_create(nmbs_t* nmbs, uint8_t address_rtu, const nmbs_platform_conf* platform_conf, const nmbs_callbacks* callbacks) { if (platform_conf->transport == NMBS_TRANSPORT_RTU && address_rtu == 0) @@ -142,6 +144,7 @@ nmbs_error nmbs_server_create(nmbs_t* nmbs, uint8_t address_rtu, const nmbs_plat return NMBS_ERROR_NONE; } +#endif void nmbs_set_read_timeout(nmbs_t* nmbs, int32_t timeout_ms) { @@ -314,7 +317,7 @@ static nmbs_error recv_msg_header(nmbs_t* nmbs, bool* first_byte_received) { return NMBS_ERROR_NONE; } - +#ifndef NMBS_SERVER_DISABLED static nmbs_error recv_req_header(nmbs_t* nmbs, bool* first_byte_received) { nmbs_error err = recv_msg_header(nmbs, first_byte_received); if (err != NMBS_ERROR_NONE) @@ -332,7 +335,7 @@ static nmbs_error recv_req_header(nmbs_t* nmbs, bool* first_byte_received) { return NMBS_ERROR_NONE; } - +#endif static nmbs_error recv_res_header(nmbs_t* nmbs) { uint16_t req_transaction_id = nmbs->msg.transaction_id; @@ -409,19 +412,23 @@ static nmbs_error send_msg_footer(nmbs_t* nmbs) { return err; } - +#ifndef NMBS_CLIENT_DISABLED static void send_req_header(nmbs_t* nmbs, uint16_t data_length) { send_msg_header(nmbs, data_length); DEBUG("NMBS req -> fc %d\t", nmbs->msg.fc); } +#endif +#ifndef NMBS_SERVER_DISABLED static void send_res_header(nmbs_t* nmbs, uint16_t data_length) { send_msg_header(nmbs, data_length); DEBUG("NMBS res -> fc %d\t", nmbs->msg.fc); } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_exception(nmbs_t* nmbs, uint8_t exception) { nmbs->msg.fc += 0x80; send_msg_header(nmbs, 1); @@ -431,8 +438,10 @@ static nmbs_error handle_exception(nmbs_t* nmbs, uint8_t exception) { return send_msg_footer(nmbs); } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_read_discrete(nmbs_t* nmbs, nmbs_error (*callback)(uint16_t, uint16_t, nmbs_bitfield)) { nmbs_error err = recv(nmbs, 4); if (err != NMBS_ERROR_NONE) @@ -490,8 +499,10 @@ static nmbs_error handle_read_discrete(nmbs_t* nmbs, nmbs_error (*callback)(uint return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_read_registers(nmbs_t* nmbs, nmbs_error (*callback)(uint16_t, uint16_t, uint16_t*)) { nmbs_error err = recv(nmbs, 4); if (err != NMBS_ERROR_NONE) @@ -549,28 +560,38 @@ static nmbs_error handle_read_registers(nmbs_t* nmbs, nmbs_error (*callback)(uin return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_read_coils(nmbs_t* nmbs) { return handle_read_discrete(nmbs, nmbs->callbacks.read_coils); } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_read_discrete_inputs(nmbs_t* nmbs) { return handle_read_discrete(nmbs, nmbs->callbacks.read_discrete_inputs); } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_read_holding_registers(nmbs_t* nmbs) { return handle_read_registers(nmbs, nmbs->callbacks.read_holding_registers); } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_read_input_registers(nmbs_t* nmbs) { return handle_read_registers(nmbs, nmbs->callbacks.read_input_registers); } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_write_single_coil(nmbs_t* nmbs) { nmbs_error err = recv(nmbs, 4); if (err != NMBS_ERROR_NONE) @@ -617,8 +638,10 @@ static nmbs_error handle_write_single_coil(nmbs_t* nmbs) { return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_write_single_register(nmbs_t* nmbs) { nmbs_error err = recv(nmbs, 4); if (err != NMBS_ERROR_NONE) @@ -662,8 +685,10 @@ static nmbs_error handle_write_single_register(nmbs_t* nmbs) { return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_write_multiple_coils(nmbs_t* nmbs) { nmbs_error err = recv(nmbs, 5); if (err != NMBS_ERROR_NONE) @@ -730,8 +755,10 @@ static nmbs_error handle_write_multiple_coils(nmbs_t* nmbs) { return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_write_multiple_registers(nmbs_t* nmbs) { nmbs_error err = recv(nmbs, 5); if (err != NMBS_ERROR_NONE) @@ -798,8 +825,10 @@ static nmbs_error handle_write_multiple_registers(nmbs_t* nmbs) { return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_SERVER_DISABLED static nmbs_error handle_req_fc(nmbs_t* nmbs) { DEBUG("fc %d\t", nmbs->msg.fc); @@ -843,8 +872,10 @@ static nmbs_error handle_req_fc(nmbs_t* nmbs) { return err; } +#endif +#ifndef NMBS_SERVER_DISABLED nmbs_error nmbs_server_poll(nmbs_t* nmbs) { msg_state_reset(nmbs); @@ -875,8 +906,10 @@ nmbs_error nmbs_server_poll(nmbs_t* nmbs) { return err; } +#endif +#ifndef NMBS_CLIENT_DISABLED static nmbs_error read_discrete(nmbs_t* nmbs, uint8_t fc, uint16_t address, uint16_t quantity, nmbs_bitfield values) { if (quantity < 1 || quantity > 2000) return NMBS_ERROR_INVALID_ARGUMENT; @@ -923,18 +956,24 @@ static nmbs_error read_discrete(nmbs_t* nmbs, uint8_t fc, uint16_t address, uint return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_CLIENT_DISABLED nmbs_error nmbs_read_coils(nmbs_t* nmbs, uint16_t address, uint16_t quantity, nmbs_bitfield coils_out) { return read_discrete(nmbs, 1, address, quantity, coils_out); } +#endif +#ifndef NMBS_CLIENT_DISABLED nmbs_error nmbs_read_discrete_inputs(nmbs_t* nmbs, uint16_t address, uint16_t quantity, nmbs_bitfield inputs_out) { return read_discrete(nmbs, 2, address, quantity, inputs_out); } +#endif +#ifndef NMBS_CLIENT_DISABLED static nmbs_error read_registers(nmbs_t* nmbs, uint8_t fc, uint16_t address, uint16_t quantity, uint16_t* registers) { if (quantity < 1 || quantity > 125) return NMBS_ERROR_INVALID_ARGUMENT; @@ -984,18 +1023,24 @@ static nmbs_error read_registers(nmbs_t* nmbs, uint8_t fc, uint16_t address, uin return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_CLIENT_DISABLED nmbs_error nmbs_read_holding_registers(nmbs_t* nmbs, uint16_t address, uint16_t quantity, uint16_t* registers_out) { return read_registers(nmbs, 3, address, quantity, registers_out); } +#endif +#ifndef NMBS_CLIENT_DISABLED nmbs_error nmbs_read_input_registers(nmbs_t* nmbs, uint16_t address, uint16_t quantity, uint16_t* registers_out) { return read_registers(nmbs, 4, address, quantity, registers_out); } +#endif +#ifndef NMBS_CLIENT_DISABLED nmbs_error nmbs_write_single_coil(nmbs_t* nmbs, uint16_t address, bool value) { msg_state_req(nmbs, 5); send_req_header(nmbs, 4); @@ -1038,8 +1083,10 @@ nmbs_error nmbs_write_single_coil(nmbs_t* nmbs, uint16_t address, bool value) { return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_CLIENT_DISABLED nmbs_error nmbs_write_single_register(nmbs_t* nmbs, uint16_t address, uint16_t value) { msg_state_req(nmbs, 6); send_req_header(nmbs, 4); @@ -1079,8 +1126,10 @@ nmbs_error nmbs_write_single_register(nmbs_t* nmbs, uint16_t address, uint16_t v return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_CLIENT_DISABLED nmbs_error nmbs_write_multiple_coils(nmbs_t* nmbs, uint16_t address, uint16_t quantity, const nmbs_bitfield coils) { if (quantity < 1 || quantity > 0x07B0) return NMBS_ERROR_INVALID_ARGUMENT; @@ -1134,8 +1183,10 @@ nmbs_error nmbs_write_multiple_coils(nmbs_t* nmbs, uint16_t address, uint16_t qu return NMBS_ERROR_NONE; } +#endif +#ifndef NMBS_CLIENT_DISABLED nmbs_error nmbs_write_multiple_registers(nmbs_t* nmbs, uint16_t address, uint16_t quantity, const uint16_t* registers) { if (quantity < 1 || quantity > 0x007B) return NMBS_ERROR_INVALID_ARGUMENT; @@ -1189,6 +1240,7 @@ nmbs_error nmbs_write_multiple_registers(nmbs_t* nmbs, uint16_t address, uint16_ return NMBS_ERROR_NONE; } +#endif nmbs_error nmbs_send_raw_pdu(nmbs_t* nmbs, uint8_t fc, const void* data, uint32_t data_len) { diff --git a/nanomodbus.h b/nanomodbus.h index ff63087..9e083d9 100644 --- a/nanomodbus.h +++ b/nanomodbus.h @@ -167,7 +167,7 @@ typedef struct nmbs_t { */ static const uint8_t NMBS_BROADCAST_ADDRESS = 0; - +#ifndef NMBS_CLIENT_DISABLED /** Create a new Modbus client. * @param nmbs pointer to the nmbs_t instance where the client will be created. * @param platform_conf nmbs_platform_conf struct with platform configuration. @@ -175,7 +175,9 @@ static const uint8_t NMBS_BROADCAST_ADDRESS = 0; * @return NMBS_ERROR_NONE if successful, NMBS_ERROR_INVALID_ARGUMENT otherwise. */ nmbs_error nmbs_client_create(nmbs_t* nmbs, const nmbs_platform_conf* platform_conf); +#endif +#ifndef NMBS_SERVER_DISABLED /** Create a new Modbus server. * @param nmbs pointer to the nmbs_t instance where the client will be created. * @param address_rtu RTU address of this server. Can be 0 if transport is not RTU. @@ -186,6 +188,7 @@ nmbs_error nmbs_client_create(nmbs_t* nmbs, const nmbs_platform_conf* platform_c */ nmbs_error nmbs_server_create(nmbs_t* nmbs, uint8_t address_rtu, const nmbs_platform_conf* platform_conf, const nmbs_callbacks* callbacks); +#endif /** Set the request/response timeout. * If the target instance is a server, sets the timeout of the nmbs_server_poll() function. @@ -213,12 +216,15 @@ void nmbs_set_byte_spacing(nmbs_t* nmbs, uint32_t spacing_ms); */ void nmbs_set_platform_arg(nmbs_t* nmbs, void* arg); +#ifndef NMBS_CLIENT_DISABLED /** Set the recipient server address of the next request on RTU transport. * @param nmbs pointer to the nmbs_t instance * @param address server address */ void nmbs_set_destination_rtu_address(nmbs_t* nmbs, uint8_t address); +#endif +#ifndef NMBS_SERVER_DISABLED /** 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 nmbs_set_read_timeout() (unless set to < 0). @@ -227,7 +233,9 @@ void nmbs_set_destination_rtu_address(nmbs_t* nmbs, uint8_t address); * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_server_poll(nmbs_t* nmbs); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Send a FC 01 (0x01) Read Coils request * @param nmbs pointer to the nmbs_t instance * @param address starting address @@ -237,7 +245,9 @@ nmbs_error nmbs_server_poll(nmbs_t* nmbs); * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_read_coils(nmbs_t* nmbs, uint16_t address, uint16_t quantity, nmbs_bitfield coils_out); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Send a FC 02 (0x02) Read Discrete Inputs request * @param nmbs pointer to the nmbs_t instance * @param address starting address @@ -247,7 +257,9 @@ nmbs_error nmbs_read_coils(nmbs_t* nmbs, uint16_t address, uint16_t quantity, nm * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_read_discrete_inputs(nmbs_t* nmbs, uint16_t address, uint16_t quantity, nmbs_bitfield inputs_out); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Send a FC 03 (0x03) Read Holding Registers request * @param nmbs pointer to the nmbs_t instance * @param address starting address @@ -257,7 +269,9 @@ nmbs_error nmbs_read_discrete_inputs(nmbs_t* nmbs, uint16_t address, uint16_t qu * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_read_holding_registers(nmbs_t* nmbs, uint16_t address, uint16_t quantity, uint16_t* registers_out); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Send a FC 04 (0x04) Read Input Registers request * @param nmbs pointer to the nmbs_t instance * @param address starting address @@ -267,7 +281,9 @@ nmbs_error nmbs_read_holding_registers(nmbs_t* nmbs, uint16_t address, uint16_t * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_read_input_registers(nmbs_t* nmbs, uint16_t address, uint16_t quantity, uint16_t* registers_out); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Send a FC 05 (0x05) Write Single Coil request * @param nmbs pointer to the nmbs_t instance * @param address coil address @@ -276,7 +292,9 @@ nmbs_error nmbs_read_input_registers(nmbs_t* nmbs, uint16_t address, uint16_t qu * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_write_single_coil(nmbs_t* nmbs, uint16_t address, bool value); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Send a FC 06 (0x06) Write Single Register request * @param nmbs pointer to the nmbs_t instance * @param address register address @@ -285,7 +303,9 @@ nmbs_error nmbs_write_single_coil(nmbs_t* nmbs, uint16_t address, bool value); * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_write_single_register(nmbs_t* nmbs, uint16_t address, uint16_t value); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Send a FC 15 (0x0F) Write Multiple Coils * @param nmbs pointer to the nmbs_t instance * @param address starting address @@ -295,7 +315,9 @@ nmbs_error nmbs_write_single_register(nmbs_t* nmbs, uint16_t address, uint16_t v * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_write_multiple_coils(nmbs_t* nmbs, uint16_t address, uint16_t quantity, const nmbs_bitfield coils); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Send a FC 16 (0x10) Write Multiple Registers * @param nmbs pointer to the nmbs_t instance * @param address starting address @@ -305,7 +327,9 @@ nmbs_error nmbs_write_multiple_coils(nmbs_t* nmbs, uint16_t address, uint16_t qu * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_write_multiple_registers(nmbs_t* nmbs, uint16_t address, uint16_t quantity, const uint16_t* registers); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Send a raw Modbus PDU. * CRC on RTU will be calculated and sent by this function. * @param nmbs pointer to the nmbs_t instance @@ -316,7 +340,9 @@ nmbs_error nmbs_write_multiple_registers(nmbs_t* nmbs, uint16_t address, uint16_ * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_send_raw_pdu(nmbs_t* nmbs, uint8_t fc, const void* data, uint32_t data_len); +#endif +#ifndef NMBS_CLIENT_DISABLED /** Receive a raw response Modbus PDU. * @param nmbs pointer to the nmbs_t instance * @param data_out response data. It's up to the caller to convert this data to host byte order. @@ -325,6 +351,7 @@ nmbs_error nmbs_send_raw_pdu(nmbs_t* nmbs, uint8_t fc, const void* data, uint32_ * @return NMBS_ERROR_NONE if successful, other errors otherwise. */ nmbs_error nmbs_receive_raw_pdu_response(nmbs_t* nmbs, void* data_out, uint32_t data_out_len); +#endif #ifndef NMBS_STRERROR_DISABLED /** Convert a nmbs_error to string diff --git a/tests/client_disabled.c b/tests/client_disabled.c new file mode 100644 index 0000000..bce77b8 --- /dev/null +++ b/tests/client_disabled.c @@ -0,0 +1,46 @@ +#define NMBS_CLIENT_DISABLED + +#include + +#include "nanomodbus.h" + +#define UNUSED_PARAM(x) ((x) = (x)) + + +int read_byte_empty(uint8_t* b, int32_t timeout, void* arg) { + UNUSED_PARAM(b); + UNUSED_PARAM(timeout); + UNUSED_PARAM(arg); + return 0; +} + + +int write_byte_empty(uint8_t b, int32_t timeout, void* arg) { + UNUSED_PARAM(b); + UNUSED_PARAM(timeout); + UNUSED_PARAM(arg); + return 0; +} + + +void platform_sleep(uint32_t milliseconds, void* arg) { + UNUSED_PARAM(arg); + usleep(milliseconds * 1000); +} + +int main() { + nmbs_t nmbs; + + nmbs_platform_conf platform_conf_empty = {.transport = NMBS_TRANSPORT_TCP, + .read_byte = read_byte_empty, + .write_byte = write_byte_empty, + .sleep = platform_sleep}; + + nmbs_callbacks callbacks_empty; + + nmbs_error err = nmbs_server_create(&nmbs, 1, &platform_conf_empty, &callbacks_empty); + if(err != 0) + return 1; + + return 0; +} diff --git a/tests/server_disabled.c b/tests/server_disabled.c new file mode 100644 index 0000000..38379cd --- /dev/null +++ b/tests/server_disabled.c @@ -0,0 +1,44 @@ +#define NMBS_SERVER_DISABLED + +#include + +#include "nanomodbus.h" + +#define UNUSED_PARAM(x) ((x) = (x)) + + +int read_byte_empty(uint8_t* b, int32_t timeout, void* arg) { + UNUSED_PARAM(b); + UNUSED_PARAM(timeout); + UNUSED_PARAM(arg); + return 0; +} + + +int write_byte_empty(uint8_t b, int32_t timeout, void* arg) { + UNUSED_PARAM(b); + UNUSED_PARAM(timeout); + UNUSED_PARAM(arg); + return 0; +} + + +void platform_sleep(uint32_t milliseconds, void* arg) { + UNUSED_PARAM(arg); + usleep(milliseconds * 1000); +} + +int main() { + nmbs_t nmbs; + + nmbs_platform_conf platform_conf_empty = {.transport = NMBS_TRANSPORT_TCP, + .read_byte = read_byte_empty, + .write_byte = write_byte_empty, + .sleep = platform_sleep}; + + nmbs_error err = nmbs_client_create(&nmbs, &platform_conf_empty); + if(err != 0) + return 1; + + return 0; +}