### CMake Build Configuration for nanomodbus TCP Examples Source: https://github.com/debevv/nanomodbus/blob/master/CMakeLists.txt Configures the build for TCP client and server examples if BUILD_EXAMPLES is enabled. It creates executable targets for 'client-tcp' and 'server-tcp' and links them against the nanomodbus library. ```cmake if (BUILD_EXAMPLES) add_executable(client-tcp examples/linux/client-tcp.c) target_link_libraries(client-tcp nanomodbus) add_executable(server-tcp examples/linux/server-tcp.c) target_link_libraries(server-tcp nanomodbus) endif () ``` -------------------------------- ### Build nanomodbus Tests and Examples on Linux Source: https://github.com/debevv/nanomodbus/blob/master/README.md Instructions for building and running nanomodbus tests and examples on Linux using CMake. This process involves creating a build directory, configuring the build with CMake, and then compiling the project. ```sh mkdir build && cd build cmake .. make ``` -------------------------------- ### Device Identification Example (C) Source: https://context7.com/debevv/nanomodbus/llms.txt This C function demonstrates how to query device information using the nanomodbus library's Read Device Identification function. It shows how to retrieve basic device identification details like vendor name, product code, and revision, as well as extended identification information. The example uses `nmbs_read_device_identification_basic` and `nmbs_read_device_identification_extended` for comprehensive device querying. ```c #include "nanomodbus.h" void device_identification_example(nmbs_t* nmbs) { char vendor_name[128]; char product_code[128]; char revision[128]; // Read basic device identification (Object IDs 0x00-0x02) nmbs_error err = nmbs_read_device_identification_basic( nmbs, vendor_name, product_code, revision, 128 ); if (err != NMBS_ERROR_NONE) { printf("Error reading device identification: %s\n", nmbs_strerror(err)); return; } printf("Device Information:\n"); printf(" Vendor: %s\n", vendor_name); printf(" Product: %s\n", product_code); printf(" Revision: %s\n", revision); // Read extended device identification char* buffers[8]; char mem[8 * 128]; for (int i = 0; i < 8; i++) { buffers[i] = &mem[i * 128]; } uint8_t ids[8]; uint8_t objects_count = 0; err = nmbs_read_device_identification_extended( nmbs, 0x80, ids, buffers, 8, 128, &objects_count ); if (err == NMBS_ERROR_NONE) { printf("\nExtended Information:\n"); for (int i = 0; i < objects_count; i++) { printf(" ID 0x%02X: %s\n", ids[i], buffers[i]); } } else if (err == NMBS_ERROR_INVALID_ARGUMENT) { printf("Buffer too small for all extended objects\n"); } } ``` -------------------------------- ### Build nanomodbus Project with CMake Source: https://github.com/debevv/nanomodbus/blob/master/examples/stm32/readme.md Standard CMake build process for the nanomodbus project. This involves creating a build directory, configuring the project with CMake, and then building using make. ```bash mkdir build cd buildcmake .. make -j16 ``` -------------------------------- ### File Record Operations Example (C) Source: https://context7.com/debevv/nanomodbus/llms.txt This C function demonstrates how to read and write file records using the nanomodbus library. It showcases the `nmbs_write_file_record` and `nmbs_read_file_record` functions for handling complex data structures within Modbus devices. The example writes an array of 16-bit values to a specified file and record, then reads them back and prints the contents. ```c #include "nanomodbus.h" void file_record_example(nmbs_t* nmbs) { // Write file record: file 1, starting at record 0 uint16_t write_data[8] = {0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888}; nmbs_error err = nmbs_write_file_record(nmbs, 1, 0, write_data, 8); if (err != NMBS_ERROR_NONE) { printf("Error writing file record: %s\n", nmbs_strerror(err)); return; } // Read file record: file 1, starting at record 0 uint16_t read_data[8]; err = nmbs_read_file_record(nmbs, 1, 0, read_data, 8); if (err != NMBS_ERROR_NONE) { printf("Error reading file record: %s\n", nmbs_strerror(err)); return; } // Display read data printf("File record contents:\n"); for (int i = 0; i < 8; i++) { printf(" Record %d: 0x%04X\n", i, read_data[i]); } } ``` -------------------------------- ### TCP Client Connection Example (C) Source: https://context7.com/debevv/nanomodbus/llms.txt This C code demonstrates a complete TCP client connection using Linux sockets and the nanomodbus library. It includes functions for custom TCP read and write operations with timeouts, setting up the Modbus client configuration, and performing basic read/write operations on registers. The example connects to a Modbus TCP server at a specified IP address and port. ```c #include "nanomodbus.h" #include #include #include #include int32_t tcp_read(uint8_t* buf, uint16_t count, int32_t timeout_ms, void* arg) { int fd = *(int*)arg; uint16_t total = 0; while (total < count) { fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds); struct timeval tv = {.tv_sec = timeout_ms / 1000, .tv_usec = (timeout_ms % 1000) * 1000}; struct timeval* tv_ptr = (timeout_ms >= 0) ? &tv : NULL; int ret = select(fd + 1, &rfds, NULL, NULL, tv_ptr); if (ret == 0) return total; // Timeout if (ret < 0) return -1; // Error ssize_t r = read(fd, buf + total, count - total); if (r <= 0) return (r == 0) ? total : -1; total += r; } return total; } int32_t tcp_write(const uint8_t* buf, uint16_t count, int32_t timeout_ms, void* arg) { int fd = *(int*)arg; ssize_t w = write(fd, buf, count); return (w > 0) ? w : -1; } int main(int argc, char* argv[]) { // Connect to server int sockfd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in server_addr = { .sin_family = AF_INET, .sin_port = htons(502), .sin_addr.s_addr = inet_addr("192.168.1.100") }; if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { printf("Connection failed\n"); return 1; } // Setup Modbus client nmbs_platform_conf platform_conf; nmbs_platform_conf_create(&platform_conf); platform_conf.transport = NMBS_TRANSPORT_TCP; platform_conf.read = tcp_read; platform_conf.write = tcp_write; platform_conf.arg = &sockfd; nmbs_t nmbs; if (nmbs_client_create(&nmbs, &platform_conf) != NMBS_ERROR_NONE) { close(sockfd); return 1; } nmbs_set_read_timeout(&nmbs, 1000); // Perform operations uint16_t registers[2] = {123, 456}; nmbs_error err = nmbs_write_multiple_registers(&nmbs, 0, 2, registers); if (err == NMBS_ERROR_NONE) { printf("Write successful\n"); } uint16_t read_regs[2]; err = nmbs_read_holding_registers(&nmbs, 0, 2, read_regs); if (err == NMBS_ERROR_NONE) { printf("Read values: %u, %u\n", read_regs[0], read_regs[1]); } close(sockfd); return 0; } ``` -------------------------------- ### C Modbus TCP Client Example Source: https://github.com/debevv/nanomodbus/blob/master/README.md Demonstrates setting up a Modbus TCP client, connecting to a server, writing holding registers, and reading holding registers using the nanoMODBUS library. It requires user-defined platform functions for TCP transport. ```C #include #include "nanomodbus.h" #include "my_platform_stuff.h" int main(int argc, char* argv[]) { // Set up the TCP connection void* conn = my_connect_tcp(argv[1], argv[2]); if (!conn) { fprintf(stderr, "Error connecting to server\n"); return 1; } // my_transport_read() and my_transport_write() are implemented by the user nmbs_platform_conf platform_conf; nmbs_platform_conf_create(&platform_conf); platform_conf.transport = NMBS_TRANSPORT_TCP; platform_conf.read = my_transport_read; platform_conf.write = my_transport_write; platform_conf.arg = conn; // Passing our TCP connection handle to the read/write functions // Create the modbus client nmbs_t nmbs; nmbs_error err = nmbs_client_create(&nmbs, &platform_conf); if (err != NMBS_ERROR_NONE) { fprintf(stderr, "Error creating modbus client\n"); return 1; } // Set only the response timeout. Byte timeout will be handled by the TCP connection nmbs_set_read_timeout(&nmbs, 1000); // Write 2 holding registers at address 26 uint16_t w_regs[2] = {123, 124}; err = nmbs_write_multiple_registers(&nmbs, 26, 2, w_regs); if (err != NMBS_ERROR_NONE) { fprintf(stderr, "Error writing register at address 26 - %s", nmbs_strerror(err)); return 1; } // Read 2 holding registers from address 26 uint16_t r_regs[2]; err = nmbs_read_holding_registers(&nmbs, 26, 2, r_regs); if (err != NMBS_ERROR_NONE) { fprintf(stderr, "Error reading 2 holding registers at address 26 - %s\n", nmbs_strerror(err)); return 1; } // Close the TCP connection my_disconnect(conn); return 0; } ``` -------------------------------- ### Configure RTU Serial Communication with Nanomodbus Source: https://context7.com/debevv/nanomodbus/llms.txt Sets up Modbus RTU communication on an embedded microcontroller, demonstrated with a Raspberry Pi Pico example. This involves initializing the UART peripheral, configuring GPIO pins for serial communication, and creating a Nanomodbus client with custom read and write functions tailored for RTU transport. The example also shows how to set timeouts and the destination RTU address, followed by a basic read operation. ```c #include "nanomodbus.h" #include "hardware/uart.h" // Raspberry Pi Pico RTU example int32_t rtu_read(uint8_t* buf, uint16_t count, int32_t timeout_ms, void* arg) { uart_inst_t* uart = (uart_inst_t*)arg; uint64_t start = time_us_64(); uint64_t timeout_us = timeout_ms * 1000; int bytes_read = 0; while (bytes_read < count) { if (time_us_64() - start > timeout_us) { break; // Timeout } if (uart_is_readable(uart)) { buf[bytes_read++] = uart_getc(uart); start = time_us_64(); // Reset timeout on each byte } } return bytes_read; } int32_t rtu_write(const uint8_t* buf, uint16_t count, int32_t timeout_ms, void* arg) { uart_inst_t* uart = (uart_inst_t*)arg; uart_write_blocking(uart, buf, count); return count; } int main(void) { // Initialize UART for RS485 uart_inst_t* uart = uart0; uart_init(uart, 19200); uart_set_format(uart, 8, 1, UART_PARITY_EVEN); // Configure GPIO pins gpio_set_function(0, GPIO_FUNC_UART); // TX gpio_set_function(1, GPIO_FUNC_UART); // RX // Create Modbus RTU client nmbs_platform_conf platform_conf; nmbs_platform_conf_create(&platform_conf); platform_conf.transport = NMBS_TRANSPORT_RTU; platform_conf.read = rtu_read; platform_conf.write = rtu_write; platform_conf.arg = uart; nmbs_t nmbs; nmbs_client_create(&nmbs, &platform_conf); nmbs_set_read_timeout(&nmbs, 1000); nmbs_set_byte_timeout(&nmbs, 50); nmbs_set_destination_rtu_address(&nmbs, 1); // Perform RTU operations uint16_t registers[4]; nmbs_error err = nmbs_read_holding_registers(&nmbs, 0, 4, registers); if (err == NMBS_ERROR_NONE) { printf("RTU read successful\n"); } return 0; } ``` -------------------------------- ### C Modbus Server Implementation with Register Callbacks Source: https://context7.com/debevv/nanomodbus/llms.txt Provides an example of setting up a Modbus server in C using the nanomodbus library. It includes custom callback functions to handle read and write requests for holding registers. The server is configured for TCP transport and features validation for data addresses to prevent out-of-bounds access. It uses platform configurations and callback structures to define server behavior. ```c #include "nanomodbus.h" // Data model #define COILS_MAX 100 #define REGS_MAX 50 nmbs_bitfield server_coils = {0}; uint16_t server_registers[REGS_MAX + 1] = {0}; // Callback: handle read holding registers request nmbs_error handle_read_registers(uint16_t address, uint16_t quantity, uint16_t* registers_out, uint8_t unit_id, void* arg) { // Validate address range if (address + quantity > REGS_MAX + 1) { return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS; } // Copy data to response buffer for (int i = 0; i < quantity; i++) { registers_out[i] = server_registers[address + i]; } return NMBS_ERROR_NONE; } // Callback: handle write multiple registers request nmbs_error handle_write_registers(uint16_t address, uint16_t quantity, const uint16_t* registers, uint8_t unit_id, void* arg) { if (address + quantity > REGS_MAX + 1) { return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS; } // Update server data model for (int i = 0; i < quantity; i++) { server_registers[address + i] = registers[i]; } return NMBS_ERROR_NONE; } int server_main(void) { // Setup platform configuration (TCP or RTU) nmbs_platform_conf platform_conf; nmbs_platform_conf_create(&platform_conf); platform_conf.transport = NMBS_TRANSPORT_TCP; platform_conf.read = my_tcp_read; platform_conf.write = my_tcp_write; platform_conf.arg = tcp_connection; // Configure callbacks nmbs_callbacks callbacks; nmbs_callbacks_create(&callbacks); callbacks.read_holding_registers = handle_read_registers; callbacks.write_multiple_registers = handle_write_registers; // Create server instance (RTU address 1, or 0 for TCP) nmbs_t nmbs; nmbs_error err = nmbs_server_create(&nmbs, 1, &platform_conf, &callbacks); if (err != NMBS_ERROR_NONE) { printf("Error creating server: %s\n", nmbs_strerror(err)); return 1; } nmbs_set_read_timeout(&nmbs, 1000); // Main server loop while (1) { err = nmbs_server_poll(&nmbs); if (err != NMBS_ERROR_NONE) { printf("Server error: %s\n", nmbs_strerror(err)); } } return 0; } ``` -------------------------------- ### Combine Read/Write Registers with Nanomodbus Source: https://context7.com/debevv/nanomodbus/llms.txt Performs an atomic read and write operation on Modbus registers in a single transaction using the nmbs_read_write_registers function. This function takes the Modbus client, read parameters (start address, quantity, buffer), and write parameters (start address, quantity, data) as input. It returns an error code indicating the success or failure of the operation. The read data is stored in the provided buffer. ```c #include "nanomodbus.h" void read_write_registers_example(nmbs_t* nmbs) { // Prepare data to write to addresses 100-104 uint16_t write_values[5] = {10, 20, 30, 40, 50}; // Buffer for reading addresses 200-209 uint16_t read_values[10]; // Atomic read/write operation nmbs_error err = nmbs_read_write_registers( nmbs, 200, 10, read_values, // Read 10 registers from address 200 100, 5, write_values // Write 5 registers to address 100 ); if (err != NMBS_ERROR_NONE) { printf("Error in read/write operation: %s\n", nmbs_strerror(err)); return; } // Process read data printf("Read values from addresses 200-209:\n"); for (int i = 0; i < 10; i++) { printf(" [%d] = %u\n", 200 + i, read_values[i]); } } ``` -------------------------------- ### C Modbus Error Handling Example Source: https://context7.com/debevv/nanomodbus/llms.txt Demonstrates how to check for and interpret various Modbus errors returned by the nanoMODBUS library. It differentiates between library-level communication errors and Modbus-specific exceptions reported by the server, providing user-friendly messages for each. This function requires a valid nmbs_t context and checks the return value of nmbs_read_holding_registers. ```c #include "nanomodbus.h" void error_handling_example(nmbs_t* nmbs) { uint16_t registers[10]; nmbs_error err = nmbs_read_holding_registers(nmbs, 100, 10, registers); // Check for errors if (err != NMBS_ERROR_NONE) { // Distinguish between library errors and Modbus exceptions if (nmbs_error_is_exception(err)) { // Modbus exception from server switch (err) { case NMBS_EXCEPTION_ILLEGAL_FUNCTION: printf("Server does not support this function\n"); break; case NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS: printf("Invalid address range\n"); break; case NMBS_EXCEPTION_ILLEGAL_DATA_VALUE: printf("Invalid data value\n"); break; case NMBS_EXCEPTION_SERVER_DEVICE_FAILURE: printf("Server device failure\n"); break; } } else { // Library/communication error switch (err) { case NMBS_ERROR_TIMEOUT: printf("Communication timeout\n"); break; case NMBS_ERROR_TRANSPORT: printf("Transport layer error\n"); break; case NMBS_ERROR_CRC: printf("CRC check failed (RTU)\n"); break; case NMBS_ERROR_INVALID_RESPONSE: printf("Invalid response received\n"); break; case NMBS_ERROR_INVALID_ARGUMENT: printf("Invalid function argument\n"); break; case NMBS_ERROR_INVALID_TCP_MBAP: printf("Invalid TCP MBAP header\n"); break; default: printf("Unknown error\n"); } } // Convert error to string printf("Error details: %s\n", nmbs_strerror(err)); return; } // Success - process data printf("Successfully read registers\n"); } ``` -------------------------------- ### Write Multiple Modbus Registers - C Source: https://context7.com/debevv/nanomodbus/llms.txt Writes multiple 16-bit values to holding registers on a Modbus server, starting at a specified address. This function is used for configuring or updating data on Modbus devices. It includes a verification step by reading back the written registers to ensure data integrity. The function requires a Modbus client instance, the starting address, the number of registers to write, and an array of the values to be written. ```c #include "nanomodbus.h" void write_multiple_registers_example(nmbs_t* nmbs) { // Prepare data to write uint16_t values[5] = {1000, 2000, 3000, 4000, 5000}; // Write 5 registers starting at address 50 nmbs_error err = nmbs_write_multiple_registers(nmbs, 50, 5, values); if (err != NMBS_ERROR_NONE) { printf("Error writing registers: %s\n", nmbs_strerror(err)); return; } // Verify written data uint16_t readback[5]; err = nmbs_read_holding_registers(nmbs, 50, 5, readback); if (err == NMBS_ERROR_NONE) { for (int i = 0; i < 5; i++) { if (readback[i] != values[i]) { printf("Verification failed at register %d\n", 50 + i); } } printf("Write verified successfully\n"); } } ``` -------------------------------- ### Create Modbus RTU/TCP Client with Custom Transport - C Source: https://context7.com/debevv/nanomodbus/llms.txt Initializes a Modbus client instance by providing platform-specific read and write functions for serial or TCP communication. This setup is crucial for defining how the library interacts with the underlying hardware, such as UARTs or network sockets. It requires the 'nanomodbus.h' header and defines custom transport functions (`my_read_serial`, `my_write_serial`) that handle data transfer and timeouts, along with a platform configuration structure. ```c #include "nanomodbus.h" // Platform-specific read/write functions int32_t my_read_serial(uint8_t* buf, uint16_t count, int32_t timeout_ms, void* arg) { // Read from serial port, block until count bytes read or timeout expires // Return bytes read, or <0 on error uart_t* uart = (uart_t*)arg; return uart_read_bytes(uart, buf, count, timeout_ms); } int32_t my_write_serial(const uint8_t* buf, uint16_t count, int32_t timeout_ms, void* arg) { // Write to serial port, block until count bytes written or timeout expires // Return bytes written, or <0 on error uart_t* uart = (uart_t*)arg; return uart_write_bytes(uart, buf, count, timeout_ms); } int main(void) { uart_t* uart = uart_init(UART0, 9600, UART_PARITY_EVEN); // Create platform configuration nmbs_platform_conf platform_conf; nmbs_platform_conf_create(&platform_conf); platform_conf.transport = NMBS_TRANSPORT_RTU; // or NMBS_TRANSPORT_TCP platform_conf.read = my_read_serial; platform_conf.write = my_write_serial; platform_conf.arg = uart; // Passed to read/write functions // Create client instance nmbs_t nmbs; nmbs_error err = nmbs_client_create(&nmbs, &platform_conf); if (err != NMBS_ERROR_NONE) { printf("Error creating client: %s\n", nmbs_strerror(err)); return 1; } // Configure timeouts nmbs_set_read_timeout(&nmbs, 1000); // 1 second response timeout nmbs_set_byte_timeout(&nmbs, 100); // 100ms inter-byte timeout // For RTU, set destination server address nmbs_set_destination_rtu_address(&nmbs, 1); // Server address 1 return 0; } ``` -------------------------------- ### Read Modbus Holding Registers - C Source: https://context7.com/debevv/nanomodbus/llms.txt Reads a specified number of 16-bit holding registers from a Modbus server starting at a given address. This function is essential for retrieving data from Modbus devices. It handles both Modbus exceptions and communication errors, returning the read data in a provided array. The input requires a valid `nmbs_t` client instance and the function returns an `nmbs_error` code. ```c #include "nanomodbus.h" void read_holding_registers_example(nmbs_t* nmbs) { uint16_t registers[10]; // Read 10 holding registers starting at address 100 nmbs_error err = nmbs_read_holding_registers(nmbs, 100, 10, registers); if (err != NMBS_ERROR_NONE) { if (nmbs_error_is_exception(err)) { printf("Modbus exception %d: %s\n", err, nmbs_strerror(err)); } else { printf("Communication error: %s\n", nmbs_strerror(err)); } return; } // Process received data for (int i = 0; i < 10; i++) { printf("Register %d: %u (0x%04X)\n", 100 + i, registers[i], registers[i]); } } ``` -------------------------------- ### CMake Build Configuration for Nanomodbus on Pico W Source: https://github.com/debevv/nanomodbus/blob/master/examples/rp2040/CMakeLists.txt This snippet demonstrates the CMake configuration for building the Nanomodbus project. It includes setting the minimum CMake version, including the Pico SDK, defining project specifics, checking SDK version compatibility, initializing the SDK, adding compiler options, creating the executable, setting include directories, and linking libraries. It also configures standard I/O for USB and UART. ```cmake cmake_minimum_required(VERSION 3.12) # Pull in SDK (must be before project) include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake) project(p C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) set(PICO_BOARD pico_w CACHE STRING "Board type") if (PICO_SDK_VERSION_STRING VERSION_LESS "1.2.0") message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.2.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}") endif () # Initialize the SDK pico_sdk_init() add_compile_options(-Wall -Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int -Wno-unused-function # we have some for the docs that aren't called ) if (CMAKE_C_COMPILER_ID STREQUAL "GNU") add_compile_options(-Wno-maybe-uninitialized) endif () # Create an executable for the app example using the gathered and filtered sources add_executable(rp2040 ../../nanomodbus.c rtu-client.c) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../..) # Link against the pico-sdk libraries as needed target_link_libraries(rp2040 pico_stdlib) # Link hardware libraries. More than one library can be added here separated by spaces. target_link_libraries(rp2040 hardware_rtc hardware_flash hardware_sync hardware_adc ) target_include_directories(rp2040 PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required ) pico_enable_stdio_usb(rp2040 1) pico_enable_stdio_uart(rp2040 0) pico_add_extra_outputs(rp2040) ``` -------------------------------- ### Fetch and Configure Dependencies with CMake Source: https://github.com/debevv/nanomodbus/blob/master/examples/stm32/CMakeLists.txt This snippet demonstrates how to use CMake's FetchContent module to download and integrate external libraries such as stm32-cmake, FreeRTOS-Kernel, wizchip-cmake, and nanoMODBUS. It specifies Git repositories and tags for each dependency and makes them available for use in the project. Dependencies are fetched at build time. ```cmake include(FetchContent) FetchContent_Declare( stm32_cmake GIT_REPOSITORY https://github.com/ObKo/stm32-cmake GIT_TAG v2.1.0 GIT_SHALLOW TRUE ) FetchContent_Populate(stm32_cmake) set(CMAKE_TOOLCHAIN_FILE ${stm32_cmake_SOURCE_DIR}/cmake/stm32_gcc.cmake) stm32_fetch_cmsis(F4) stm32_fetch_hal(F4) find_package(CMSIS COMPONENTS STM32F401CC REQUIRED) find_package(HAL COMPONENTS STM32F4 REQUIRED) FetchContent_Declare(freertos_kernel GIT_REPOSITORY https://github.com/FreeRTOS/FreeRTOS-Kernel.git GIT_TAG V11.1.0 GIT_SHALLOW TRUE ) FetchContent_MakeAvailable(freertos_kernel) FetchContent_Declare( wizchip GIT_REPOSITORY https://github.com/donghoonpark/wizchip-cmake GIT_SHALLOW TRUE ) FetchContent_MakeAvailable(wizchip) FetchContent_Declare( nanomodbus GIT_REPOSITORY https://github.com/debevv/nanoMODBUS GIT_TAG master GIT_SHALLOW TRUE ) FetchContent_GetProperties(nanomodbus) if (NOT nanomodbus_POPULATED) FetchContent_Populate(nanomodbus) endif () add_library(nanomodbus ${nanomodbus_SOURCE_DIR}/nanomodbus.c) target_include_directories(nanomodbus PUBLIC ${nanomodbus_SOURCE_DIR}) ``` -------------------------------- ### C CMake Project Integration Source: https://github.com/debevv/nanomodbus/blob/master/README.md Shows how to integrate the nanoMODBUS library into a CMake build system. It uses `FetchContent` to download the library from GitHub and links it to the executable. This method simplifies dependency management for projects using CMake. ```cmake FetchContent_Declare( nanomodbus GIT_REPOSITORY https://github.com/debevv/nanoMODBUS GIT_TAG master # or the version you want GIT_SHALLOW TRUE ) FetchContent_MakeAvailable(nanomodbus) #... add_executable(your_program source_codes) target_link_libraries(your_program nanomodbus) ``` -------------------------------- ### CMake Build Configuration for nanomodbus Library Source: https://github.com/debevv/nanomodbus/blob/master/CMakeLists.txt Sets up the basic CMake build for the nanomodbus library. It defines the minimum CMake version, project name, C standard, compiler flags for debug and release builds, and include directories. It then adds the nanomodbus library target. ```cmake cmake_minimum_required(VERSION 3.16) project(nanomodbus C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -Wswitch-enum -Wcast-qual -Woverflow") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -g0") include_directories(tests examples/linux .) # Define BUILD_SHARED_LIBS=ON to build a dynamic library instead add_library(nanomodbus nanomodbus.c) target_include_directories(nanomodbus PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) ``` -------------------------------- ### Define and Build Modbus Applications with CMake Source: https://github.com/debevv/nanomodbus/blob/master/examples/stm32/CMakeLists.txt This snippet defines executable targets for Modbus RTU and Modbus TCP applications. It specifies the source files, include directories, and necessary compile definitions for each target. It also links against all the required libraries including STM32 HAL, FreeRTOS, wizchip, and nanoMODBUS. The configuration is done within a foreach loop for both target names. ```cmake set(TARGET_NAMES modbus_rtu modbus_tcp) foreach (TARGET_NAME ${TARGET_NAMES}) add_executable(${TARGET_NAME} ${TARGET_NAME}.c bsp/blackpill/blackpill.c nmbs/port.c ) target_include_directories( ${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bsp ${CMAKE_CURRENT_SOURCE_DIR}/nmbs ) if (${TARGET_NAME} STREQUAL "modbus_rtu") target_compile_definitions( ${TARGET_NAME} PRIVATE NMBS_RTU ) elseif (${TARGET_NAME} STREQUAL "modbus_tcp") target_compile_definitions( ${TARGET_NAME} PRIVATE NMBS_TCP ) endif () target_link_libraries( ${TARGET_NAME} STM32::NoSys CMSIS::STM32::F401CC HAL::STM32::F4::CORTEX HAL::STM32::F4::RCC HAL::STM32::F4::PWR HAL::STM32::F4::GPIO HAL::STM32::F4::TIM HAL::STM32::F4::UART HAL::STM32::F4::USART HAL::STM32::F4::SPI HAL::STM32::F4::DMA wizchip freertos_kernel nanomodbus ) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_SIZE} $ ) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_OBJCOPY} -O ihex $ ${TARGET_NAME}.hex ) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_OBJCOPY} -O binary $ ${TARGET_NAME}.bin ) endforeach () ``` -------------------------------- ### CMake Build Configuration for nanomodbus Tests Source: https://github.com/debevv/nanomodbus/blob/master/CMakeLists.txt Sets up the build for various test executables if BUILD_TESTS is enabled. This includes a general test suite, tests with server/client disabled, and a multi-server RTU test. It also links against pthread where necessary and defines specific compile flags. ```cmake if (BUILD_TESTS) add_executable(nanomodbus_tests nanomodbus.c tests/nanomodbus_tests.c) target_link_libraries(nanomodbus_tests pthread) add_executable(server_disabled nanomodbus.c tests/server_disabled.c) target_compile_definitions(server_disabled PUBLIC NMBS_SERVER_DISABLED) add_executable(client_disabled nanomodbus.c tests/client_disabled.c) target_compile_definitions(client_disabled PUBLIC NMBS_CLIENT_DISABLED) add_executable(multi_server_rtu nanomodbus.c tests/multi_server_rtu.c) target_compile_definitions(multi_server_rtu PUBLIC NMBS_DEBUG) target_link_libraries(multi_server_rtu pthread) enable_testing() add_test(NAME test_general COMMAND $) add_test(NAME test_server_disabled COMMAND $) add_test(NAME test_client_disabled COMMAND $) add_test(NAME test_multi_server_rtu COMMAND $) endif () ``` -------------------------------- ### Read and Write Modbus Coils using C Source: https://context7.com/debevv/nanomodbus/llms.txt Demonstrates how to manipulate binary coil values using bitfield operations in C. This includes setting individual coil states, writing multiple coils to a device, and reading coils back to check their status. It utilizes functions like nmbs_bitfield_write, nmbs_write_multiple_coils, nmbs_read_coils, and nmbs_bitfield_read. ```c #include "nanomodbus.h" void coils_example(nmbs_t* nmbs) { nmbs_bitfield coils = {0}; // Set specific coil values nmbs_bitfield_write(coils, 0, 1); // Coil 0 = ON nmbs_bitfield_write(coils, 1, 1); // Coil 1 = ON nmbs_bitfield_write(coils, 2, 0); // Coil 2 = OFF nmbs_bitfield_write(coils, 3, 1); // Coil 3 = ON // Write 4 coils starting at address 64 nmbs_error err = nmbs_write_multiple_coils(nmbs, 64, 4, coils); if (err != NMBS_ERROR_NONE) { printf("Error writing coils: %s\n", nmbs_strerror(err)); return; } // Read back 10 coils starting at address 64 nmbs_bitfield_reset(coils); // Clear bitfield err = nmbs_read_coils(nmbs, 64, 10, coils); if (err != NMBS_ERROR_NONE) { printf("Error reading coils: %s\n", nmbs_strerror(err)); return; } // Read individual coil values for (int i = 0; i < 10; i++) { bool value = nmbs_bitfield_read(coils, i); printf("Coil %d: %s\n", 64 + i, value ? "ON" : "OFF"); } } ``` -------------------------------- ### Enable nanomodbus Debug Prints Source: https://github.com/debevv/nanomodbus/blob/master/README.md Enable debug messages for received and sent Modbus messages within the nanomodbus library by defining NMBS_DEBUG. This is useful for troubleshooting communication issues. ```c #define NMBS_DEBUG ``` -------------------------------- ### nanomodbus Size Reduction Defines Source: https://github.com/debevv/nanomodbus/blob/master/README.md Preprocessor directives for reducing the code size of the nanomodbus library. These defines allow disabling entire modules like client or server, specific server callbacks, or utility functions like error string conversion. ```c #define NMBS_CLIENT_DISABLED #define NMBS_SERVER_DISABLED #define NMBS_SERVER_READ_COILS_DISABLED #define NMBS_SERVER_READ_DISCRETE_INPUTS_DISABLED #define NMBS_SERVER_READ_HOLDING_REGISTERS_DISABLED #define NMBS_SERVER_READ_INPUT_REGISTERS_DISABLED #define NMBS_SERVER_WRITE_SINGLE_COIL_DISABLED #define NMBS_SERVER_WRITE_SINGLE_REGISTER_DISABLED #define NMBS_SERVER_WRITE_MULTIPLE_COILS_DISABLED #define NMBS_SERVER_WRITE_MULTIPLE_REGISTERS_DISABLED #define NMBS_SERVER_READ_FILE_RECORD_DISABLED #define NMBS_SERVER_WRITE_FILE_RECORD_DISABLED #define NMBS_SERVER_READ_WRITE_REGISTERS_DISABLED #define NMBS_SERVER_READ_DEVICE_IDENTIFICATION_DISABLED #define NMBS_STRERROR_DISABLED #define NMBS_BITFIELD_MAX 2000 ``` -------------------------------- ### C Platform Read/Write Function Signatures Source: https://github.com/debevv/nanomodbus/blob/master/README.md Defines the required function signatures for platform-specific read and write operations in nanoMODBUS. These functions handle the actual data transfer over the chosen transport (e.g., serial, TCP) and are essential for the library's operation. ```C int32_t read(uint8_t* buf, uint16_t count, int32_t byte_timeout_ms, void* arg); int32_t write(const uint8_t* buf, uint16_t count, int32_t byte_timeout_ms, void* arg); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.