### Example: Reading Holding Registers with Raw Request (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_send_raw_request_tid.md An example demonstrating how to use modbus_send_raw_request to read holding registers. It shows the setup of the Modbus context, connection, raw request construction, sending the request, and receiving the confirmation. Error handling for connection is included. ```c modbus_t *ctx; /* Read 5 holding registers from address 1 */ uint8_t raw_req[] = { 0xFF, MODBUS_FC_READ_HOLDING_REGISTERS, 0x00, 0x01, 0x0, 0x05 }; int req_length; uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH]; ctx = modbus_new_tcp("127.0.0.1", 502); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } req_length = modbus_send_raw_request(ctx, raw_req, 6 * sizeof(uint8_t), 0); modbus_receive_confirmation(ctx, rsp); modbus_close(ctx); modbus_free(ctx); ``` -------------------------------- ### Example usage of modbus_set_slave Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_set_slave.md This example demonstrates initializing an RTU context and setting the slave ID before establishing a connection. It includes error handling for both context creation and slave ID assignment. ```c modbus_t *ctx; ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1); if (ctx == NULL) { fprintf(stderr, "Unable to create the libmodbus context\n"); return -1; } rc = modbus_set_slave(ctx, YOUR_DEVICE_ID); if (rc == -1) { fprintf(stderr, "Invalid slave ID\n"); modbus_free(ctx); return -1; } if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } ``` -------------------------------- ### Configure Modbus Response Timeout Example Source: https://context7.com/stephane/libmodbus/llms.txt This C code illustrates how to configure the response timeout for Modbus TCP communication. It shows how to get the current timeout, set a new timeout value (e.g., 200ms), and handle cases where a device does not respond within the specified time by checking for the ETIMEDOUT error. The original timeout can be restored. ```c #include #include #include int main(void) { modbus_t *ctx; uint32_t old_sec, old_usec; uint16_t regs[10]; int rc; ctx = modbus_new_tcp("192.168.1.100", 502); if (modbus_connect(ctx) == -1) { modbus_free(ctx); return -1; } // Save the original timeout modbus_get_response_timeout(ctx, &old_sec, &old_usec); printf("Original timeout: %u.%06u seconds\n", old_sec, old_usec); // Set a short timeout of 200ms for fast devices modbus_set_response_timeout(ctx, 0, 200000); rc = modbus_read_registers(ctx, 0, 5, regs); if (rc == -1 && errno == ETIMEDOUT) { printf("Device did not respond within 200ms\n"); // Try with a longer timeout modbus_set_response_timeout(ctx, 1, 0); // 1 second rc = modbus_read_registers(ctx, 0, 5, regs); if (rc == -1) { printf("Device still not responding\n"); } } // Restore original timeout modbus_set_response_timeout(ctx, old_sec, old_usec); modbus_close(ctx); modbus_free(ctx); return 0; } ``` -------------------------------- ### Set Modbus Socket (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Associates a pre-existing socket file descriptor with the Modbus context. This allows the user to manage the socket externally, for example, when using non-blocking I/O or custom network setups. It requires the Modbus context and the socket file descriptor. ```c #include #include modbus_t *ctx; int sockfd; // ... create socket sockfd ... // Set the socket for the Modbus context if (modbus_set_socket(ctx, sockfd) < 0) { // Handle error } ``` -------------------------------- ### Example: Enable RTS Mode with Positive Polarity (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_rtu_set_rts.md Demonstrates enabling RTS mode with positive polarity (MODBUS_RTU_RTS_UP) for an RTU serial connection using libmodbus. This example includes setting up the serial port, connecting, configuring RTS, reading registers, and cleaning up resources. ```c modbus_t *ctx; uint16_t tab_reg[10]; ctx = modbus_new_rtu("/dev/ttyS0", 115200, 'N', 8, 1); modbus_set_slave(ctx, 1); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485); modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP); rc = modbus_read_registers(ctx, 0, 7, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; } modbus_close(ctx); modbus_free(ctx); ``` -------------------------------- ### Get Byte from Bits Array (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Constructs a byte from a sequence of bits in a Modbus bit array. This is the inverse of `modbus_set_bits_from_byte` and is useful for converting bit data back into byte format. It requires the source bit array, starting bit index, and a destination byte. ```c #include uint8_t bits_array[8] = {1, 0, 1, 0, 1, 0, 1, 0}; // Binary: 10101010 uint8_t byte_value ``` -------------------------------- ### Allocate Modbus Mapping with Custom Start Addresses (C) Source: https://context7.com/stephane/libmodbus/llms.txt Allocates a Modbus data mapping where each data type (coils, discrete inputs, holding registers, input registers) can have a specific starting address. This is useful when the Modbus device's addresses do not begin at 0. It requires the libmodbus library. ```c #include #include #include int main(void) { modbus_mapping_t *mb_mapping; // Allocate mapping with custom start addresses: // - Coils: start at 100, count 50 // - Discrete inputs: start at 200, count 30 // - Holding registers: start at 1000, count 100 // - Input registers: start at 2000, count 50 mb_mapping = modbus_mapping_new_start_address( 100, // start_bits 50, // nb_bits 200, // start_input_bits 30, // nb_input_bits 1000, // start_registers 100, // nb_registers 2000, // start_input_registers 50 // nb_input_registers ); if (mb_mapping == NULL) { fprintf(stderr, "Failed to allocate mapping: %s\n", modbus_strerror(errno)); return -1; } // Access data using offset from start address // For register at address 1000, use index 0 mb_mapping->tab_registers[0] = 0xABCD; // For register at address 1050, use index 50 mb_mapping->tab_registers[50] = 0xEF01; printf("Mapping with custom addresses allocated:\n"); printf(" Coils: %d-%d\n", mb_mapping->start_bits, mb_mapping->start_bits + mb_mapping->nb_bits - 1); printf(" Registers: %d-%d\n", mb_mapping->start_registers, mb_mapping->start_registers + mb_mapping->nb_registers - 1); modbus_mapping_free(mb_mapping); return 0; } ``` -------------------------------- ### Complete Modbus TCP Server Example (C) Source: https://context7.com/stephane/libmodbus/llms.txt Implements a Modbus TCP server that listens for incoming connections, receives Modbus requests, and sends replies. It uses functions like `modbus_new_tcp`, `modbus_tcp_listen`, `modbus_receive`, and `modbus_reply`. Requires the libmodbus library and network capabilities. ```c #include #include #include #include #include int main(void) { modbus_t *ctx; modbus_mapping_t *mb_mapping; uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH]; int server_socket; int rc; // Create TCP context listening on any address, port 1502 ctx = modbus_new_tcp(NULL, 1502); if (ctx == NULL) { fprintf(stderr, "Unable to allocate libmodbus context\n"); return -1; } // Enable debug mode to see messages modbus_set_debug(ctx, TRUE); // Allocate and initialize the memory to store Modbus data mb_mapping = modbus_mapping_new(500, 500, 500, 500); if (mb_mapping == NULL) { fprintf(stderr, "Failed to allocate mapping: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } // Initialize some test data mb_mapping->tab_registers[0] = 0x1234; mb_mapping->tab_registers[1] = 0x5678; mb_mapping->tab_input_registers[0] = 1000; mb_mapping->tab_input_registers[1] = 2000; mb_mapping->tab_bits[0] = TRUE; // Listen for incoming connections (max 1 connection) server_socket = modbus_tcp_listen(ctx, 1); if (server_socket == -1) { fprintf(stderr, "Listen failed: %s\n", modbus_strerror(errno)); modbus_mapping_free(mb_mapping); modbus_free(ctx); return -1; } printf("Waiting for connection on port 1502...\n"); // Accept a connection modbus_tcp_accept(ctx, &server_socket); printf("Client connected!\n"); // Main server loop for (;;) { // Wait for and receive a request rc = modbus_receive(ctx, query); if (rc > 0) { // Process the request and send reply rc = modbus_reply(ctx, query, rc, mb_mapping); if (rc == -1) { fprintf(stderr, "Reply failed: %s\n", modbus_strerror(errno)); break; } } else if (rc == -1) { // Connection closed or error fprintf(stderr, "Receive failed: %s\n", modbus_strerror(errno)); break; } } printf("Server shutting down\n"); close(server_socket); modbus_mapping_free(mb_mapping); modbus_close(ctx); modbus_free(ctx); return 0; } ``` -------------------------------- ### Allocate Modbus mapping with custom start addresses Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_mapping_new_start_address.md Allocates four arrays to store bits, input bits, registers, and input registers within a modbus_mapping_t structure. This function allows defining specific starting addresses for each data type, returning a pointer to the allocated structure or NULL on failure. ```c modbus_mapping_t* mb_mapping = modbus_mapping_new_start_address(0, 0, 0, 0, 340, 10, 0, 0); // Accessing the first register at address 340 mb_mapping->tab_registers[0] = 42; // Full allocation example with error handling mb_mapping = modbus_mapping_new_start_address( BITS_ADDRESS, BITS_NB, INPUT_BITS_ADDRESS, INPUT_BITS_NB, REGISTERS_ADDRESS, REGISTERS_NB, INPUT_REGISTERS_ADDRESS, INPUT_REGISTERS_NB ); if (mb_mapping == NULL) { fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno)); return -1; } ``` -------------------------------- ### Create Modbus RTU Server Example Source: https://context7.com/stephane/libmodbus/llms.txt This C code creates a Modbus RTU server on a specified serial port. It initializes the Modbus context, sets the slave ID, allocates memory for Modbus data mapping, and enters a loop to receive and respond to master requests. Error handling for context creation, mapping allocation, and connection is included. ```c #include #include #include #include #define SERVER_SLAVE_ID 1 int main(void) { modbus_t *ctx; modbus_mapping_t *mb_mapping; uint8_t query[MODBUS_RTU_MAX_ADU_LENGTH]; int rc; // Create RTU context ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1); if (ctx == NULL) { fprintf(stderr, "Unable to create RTU context\n"); return -1; } // Set the slave ID for this server modbus_set_slave(ctx, SERVER_SLAVE_ID); // Enable debug modbus_set_debug(ctx, TRUE); // Allocate mapping mb_mapping = modbus_mapping_new(500, 500, 500, 500); if (mb_mapping == NULL) { fprintf(stderr, "Failed to allocate mapping: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } // Initialize test data mb_mapping->tab_registers[0] = 0xABCD; mb_mapping->tab_input_registers[0] = 3000; // Connect to serial port if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_mapping_free(mb_mapping); modbus_free(ctx); return -1; } printf("RTU server started on slave ID %d\n", SERVER_SLAVE_ID); // Server loop for (;;) { do { rc = modbus_receive(ctx, query); // rc == 0 means the query was for another slave, ignore it } while (rc == 0); if (rc == -1 && errno != EMBBADCRC) { // Fatal error break; } if (rc > 0) { // Valid request received, send reply rc = modbus_reply(ctx, query, rc, mb_mapping); if (rc == -1) { break; } } } printf("Server stopped: %s\n", modbus_strerror(errno)); modbus_mapping_free(mb_mapping); modbus_close(ctx); modbus_free(ctx); return 0; } ``` -------------------------------- ### Set Bits from Byte Array (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Sets a sequence of bits in a Modbus bit array from a byte array. This function is useful for converting byte data into individual bit states. It requires the destination bit array, starting bit index, source byte array, starting byte index, and the number of bits to set. ```c #include uint8_t bits_array[16]; uint8_t byte_array[2] = {0x55, 0xAA}; // Binary: 01010101 10101010 // Set 16 bits starting from index 0 in bits_array from byte_array modbus_set_bits_from_bytes(bits_array, 0, byte_array, 0, 16); ``` -------------------------------- ### Get Modbus Socket (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Retrieves the socket file descriptor associated with the Modbus context. This can be useful for performing custom I/O operations or checking the socket status. It requires the Modbus context and returns the socket file descriptor. ```c #include modbus_t *ctx; int sockfd; // ... connect ... sockfd = modbus_get_socket(ctx); // Use the sockfd value... ``` -------------------------------- ### Write and Read Modbus Registers (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Performs a Modbus write and read operation on registers in a single request. This is useful for atomic updates and reads. It requires the Modbus context, data to write, starting address for writing, quantity to write, starting address for reading, and quantity to read. ```c #include modbus_t *ctx; uint16_t write_registers[2] = {100, 200}; uint16_t read_registers[3]; int rc; // ... connect and set slave ... // Write 2 registers starting at address 5, then read 3 registers starting at address 10 rc = modbus_write_and_read_registers(ctx, 5, 2, write_registers, 10, 3, read_registers); if (rc < 0) { // Handle error } else { // Process the read registers in read_registers } ``` -------------------------------- ### C Function: modbus_mapping_new_start_address Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_mapping_new_start_address.md Allocates four arrays of bits and registers accessible from specific starting addresses for a Modbus server. ```APIDOC ## FUNCTION modbus_mapping_new_start_address ### Description Allocates four arrays to store bits, input bits, registers, and input registers. The pointers are stored in a modbus_mapping_t structure, and all values are initialized to zero. This allows mapping data to specific address ranges rather than starting from zero. ### Method C Function Call ### Parameters - **start_bits** (unsigned int) - Required - Starting address for bits - **nb_bits** (unsigned int) - Required - Number of bits to allocate - **start_input_bits** (unsigned int) - Required - Starting address for input bits - **nb_input_bits** (unsigned int) - Required - Number of input bits to allocate - **start_registers** (unsigned int) - Required - Starting address for registers - **nb_registers** (unsigned int) - Required - Number of registers to allocate - **start_input_registers** (unsigned int) - Required - Starting address for input registers - **nb_input_registers** (unsigned int) - Required - Number of input registers to allocate ### Request Example ```c mb_mapping = modbus_mapping_new_start_address(0, 0, 0, 0, 340, 10, 0, 0); ``` ### Response #### Success Response - **modbus_mapping_t*** (pointer) - Pointer to the newly allocated mapping structure. #### Error Response - **NULL** (pointer) - Returns NULL if allocation fails, with errno set to ENOMEM. ``` -------------------------------- ### Set Modbus Slave ID Example Source: https://context7.com/stephane/libmodbus/llms.txt This C code demonstrates how to set the Modbus slave (unit) ID for communication. It shows how to switch the context to communicate with different slave IDs and also how to use the broadcast address. This is crucial for RTU communication and certain TCP devices. ```c #include #include #include int main(void) { modbus_t *ctx; int rc; uint16_t regs[10]; ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1); if (ctx == NULL) { return -1; } // Set slave ID to communicate with device #1 rc = modbus_set_slave(ctx, 1); if (rc == -1) { fprintf(stderr, "Invalid slave ID\n"); modbus_free(ctx); return -1; } if (modbus_connect(ctx) == -1) { modbus_free(ctx); return -1; } // Read from device #1 modbus_read_registers(ctx, 0, 5, regs); printf("Device 1, reg[0] = %d\n", regs[0]); // Switch to device #2 modbus_set_slave(ctx, 2); modbus_read_registers(ctx, 0, 5, regs); printf("Device 2, reg[0] = %d\n", regs[0]); // Use broadcast address (all devices receive, none respond) modbus_set_slave(ctx, MODBUS_BROADCAST_ADDRESS); modbus_write_register(ctx, 100, 0); // Reset all devices modbus_close(ctx); modbus_free(ctx); return 0; } ``` -------------------------------- ### Write Modbus Bit (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Writes a single Modbus bit (coil) to a device. This function is used to set the state of a discrete output or coil. It requires the Modbus context, the starting address, and the value (0 or 1) to write. ```c #include modbus_t *ctx; int rc; // ... connect and set slave ... // Write bit at address 1 to value 1 (ON) rc = modbus_write_bit(ctx, 1, 1); if (rc < 0) { // Handle error } ``` -------------------------------- ### Get Modbus Header Length (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Retrieves the length of the Modbus header used by the library. This can vary depending on the Modbus protocol variant (e.g., RTU, TCP). It requires the Modbus context. ```c #include modbus_t *ctx; int header_length; // ... connect ... header_length = modbus_get_header_length(ctx); // Use the header_length value... ``` -------------------------------- ### Get Modbus Response Timeout (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Retrieves the current response timeout setting for Modbus communication. The response timeout is the maximum time to wait for a complete Modbus response after sending a request. It requires the Modbus context. ```c #include modbus_t *ctx; int sec, usec; // ... connect ... modbus_get_response_timeout(ctx, &sec, &usec); // Use sec and usec values... ``` -------------------------------- ### Get Modbus Byte Timeout (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Retrieves the current byte timeout setting for Modbus communication. The byte timeout determines the maximum time to wait for each byte of a Modbus message. It requires the Modbus context. ```c #include modbus_t *ctx; int timeout; // ... connect ... timeout = modbus_get_byte_timeout(ctx); // Use the timeout value... ``` -------------------------------- ### Write Modbus Register (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Writes a single Modbus register (16-bit integer) to a device. This function is used to update holding registers. It requires the Modbus context, the starting address, and the 16-bit value to write. ```c #include modbus_t *ctx; int rc; // ... connect and set slave ... // Write register at address 10 with value 1234 rc = modbus_write_register(ctx, 10, 1234); if (rc < 0) { // Handle error } ``` -------------------------------- ### Set bits from bytes in C Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_set_bits_from_bytes.md This function sets multiple bits in a destination array by reading values from a source byte array. It requires a pointer to the destination bit array, the starting index, the number of bits to set, and the source byte array. ```c void modbus_set_bits_from_bytes(uint8_t *dest, int index, unsigned int nb_bits, const uint8_t *tab_byte); ``` -------------------------------- ### Write Modbus Bits (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Writes multiple Modbus bits (coils) to a device. This function allows setting the state of a range of discrete outputs or coils. It requires the Modbus context, starting address, quantity, and an array of values to write. ```c #include modbus_t *ctx; uint8_t tab_rp_bits[10] = {1, 0, 1, 1, 0, 1, 0, 0, 1, 1}; int rc; // ... connect and set slave ... // Write 10 bits starting from address 0 rc = modbus_write_bits(ctx, 0, 10, tab_rp_bits); if (rc < 0) { // Handle error } ``` -------------------------------- ### Read Modbus Input Registers (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Reads a number of Modbus input registers (16-bit unsigned integers) from a device. This function is for reading the values of input registers. It requires the Modbus context, starting address, quantity, and a destination array. ```c #include modbus_t *ctx; uint16_t tab_rp_registers[128]; int rc; // ... connect and set slave ... // Read 5 input registers starting from address 0 rc = modbus_read_input_registers(ctx, 0, 5, tab_rp_registers); if (rc < 0) { // Handle error } else { // Process the read input registers in tab_rp_registers } ``` -------------------------------- ### Accessing libmodbus Version Information Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md The library provides a string constant for compile-time versioning and integer variables for runtime linked versioning. These constants and variables allow developers to check compatibility and features at different stages of the build process. ```C /* Compile-time version */ const char *version = _LIBMODBUS_VERSION_STRING_; /* Runtime linked version */ int major = libmodbus_version_major; int minor = libmodbus_version_minor; int micro = libmodbus_version_micro; ``` -------------------------------- ### Get Modbus Byte Timeout (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_get_byte_timeout.md Retrieves the timeout interval between consecutive bytes for a Modbus message. It stores the timeout in seconds and microseconds in the provided pointers. Returns 0 on success, -1 on failure. ```c int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec); uint32_t to_sec; uint32_t to_usec; /* Save original timeout */ modbus_get_byte_timeout(ctx, &to_sec, &to_usec); ``` -------------------------------- ### Get RTU RTS Mode (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_rtu_get_rts.md Retrieves the current Request To Send (RTS) mode for a libmodbus context configured with a RTU backend. It returns the RTS mode or -1 on error. This function is specific to RTU contexts. ```c #include int modbus_rtu_get_rts(modbus_t *ctx); ``` -------------------------------- ### Get RTU Serial Mode (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_rtu_get_serial_mode.md Retrieves the current serial mode (RS232 or RS485) from a libmodbus RTU context. This function is only available on Linux kernels 2.6.28 onwards and requires an RTU backend. It returns the mode on success or -1 on failure. ```c int modbus_rtu_get_serial_mode(modbus_t *ctx); ``` -------------------------------- ### Get Modbus Response Timeout (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_get_response_timeout.md Retrieves the timeout interval for waiting for a Modbus response. It takes a modbus_t context pointer and pointers to uint32_t variables to store the seconds and microseconds of the timeout. Returns 0 on success, -1 on failure. ```c int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec); ``` ```c uint32_t old_response_to_sec; uint32_t old_response_to_usec; /* Save original timeout */ modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec); /* Define a new and too short timeout! */ modbus_set_response_timeout(ctx, 0, 0); ``` -------------------------------- ### Create Modbus Mapping (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Allocates and initializes a Modbus mapping structure. This structure is used by Modbus servers to define the memory layout for coils, discrete inputs, holding registers, and input registers. It requires the number of elements for each type. ```c #include modbus_mapping_t *mb_mapping; // Create a mapping for 1000 coils, 1000 discrete inputs, 1000 holding registers, 1000 input registers mb_mapping = modbus_mapping_new(1000, 1000, 1000, 1000); if (mb_mapping == NULL) { // Handle error } // ... populate mapping data ... // Free mapping when done // modbus_mapping_free(mb_mapping); ``` -------------------------------- ### Get Slave Number (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_get_slave.md Retrieves the slave number from the libmodbus context. This function is useful for identifying the specific Modbus slave device being communicated with. It returns the slave number on success or -1 on failure, setting errno accordingly. ```c int modbus_get_slave(modbus_t *ctx); ``` -------------------------------- ### Establish and Close Modbus Connection (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Functions to establish, close, and flush a Modbus connection. `modbus_connect` initiates the connection, `modbus_close` terminates it, and `modbus_flush` clears any buffered data. Ensure `modbus_free` is called to release resources. ```c #include modbus_t *ctx; // Establish connection ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1); if (ctx == NULL) { // Handle error } if (modbus_connect(ctx) < 0) { // Handle error } // ... perform operations ... // Close connection modbus_close(ctx); // Flush connection (optional) modbus_flush(ctx); // Free resources modbus_free(ctx); ``` -------------------------------- ### Get Float from Modbus Registers (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_get_float.md Retrieves a float value from two 16-bit unsigned integers representing Modbus data. The input `src` must be a pointer to two uint16_t values. This function is deprecated since libmodbus v3.2.0. ```c float modbus_get_float(const uint16_t *src); ``` -------------------------------- ### Create Modbus TCP Context (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_new_tcp_pi.md Allocates and initializes a modbus_t structure for Modbus TCP communication. It takes the host node and service (port) as arguments. NULL can be used for node to listen on any address in server mode, and for service to use the default port 502. Returns a pointer to the context on success, or NULL on failure. ```c modbus_t *modbus_new_tcp_pi(const char *node, const char *service); ``` ```c modbus_t *ctx; ctx = modbus_new_tcp_pi("::1", "502"); if (ctx == NULL) { fprintf(stderr, "Unable to allocate libmodbus context\n"); return -1; } if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } ``` -------------------------------- ### Create RTU Serial Modbus Context (C) Source: https://context7.com/stephane/libmodbus/llms.txt Creates a libmodbus context for serial RTU communication. Requires specifying the serial device path, baud rate, parity, data bits, and stop bits. The slave ID must be set using modbus_set_slave() before connecting. ```c #include #include #include int main(void) { modbus_t *ctx; const int REMOTE_SLAVE_ID = 1; // Create RTU context: device, baud, parity (N/E/O), data bits, stop bits ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1); if (ctx == NULL) { fprintf(stderr, "Unable to create the libmodbus context\n"); return -1; } // On Windows with COM ports > 9, use: "\\\\.\\COM10" // ctx = modbus_new_rtu("\\\\.\\COM10", 9600, 'E', 8, 1); // Set the slave ID of the remote device to communicate with if (modbus_set_slave(ctx, REMOTE_SLAVE_ID) == -1) { fprintf(stderr, "Invalid slave ID\n"); modbus_free(ctx); return -1; } // Connect to the serial bus if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } printf("Connected to RTU slave %d\n", REMOTE_SLAVE_ID); modbus_close(ctx); modbus_free(ctx); return 0; } ``` -------------------------------- ### Get RTU RTS Delay (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_rtu_get_rts_delay.md Retrieves the current Request To Send (RTS) delay period from a libmodbus context configured for RTU communication. This function is specific to RTU backends and returns the delay in microseconds upon success, or -1 if the backend is not RTU. ```c #include int rts_delay = modbus_rtu_get_rts_delay(ctx); if (rts_delay == -1) { // Handle error, e.g., check errno } ``` -------------------------------- ### Build Int64 from Int16 Array (C Macro) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md A macro to construct a 64-bit integer from four consecutive 16-bit integers in an array. This is useful for interpreting data that spans multiple registers and is represented as a larger integer type. ```c #include uint16_t data_array[4] = {0x1234, 0x5678, 0x9ABC, 0xDEF0}; int64_t value; value = MODBUS_GET_INT64_FROM_INT16(data_array, 0); // value will represent the combined 64-bit integer ``` -------------------------------- ### Establish Modbus TCP Connection (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_connect.md Establishes a Modbus TCP connection to a server using the provided context. Requires libmodbus library. Returns 0 on success, -1 on failure. ```c int modbus_connect(modbus_t *ctx); // Example: modbus_t *ctx; ctx = modbus_new_tcp("127.0.0.1", 502); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } ``` -------------------------------- ### Create TCP/IPv4 Modbus Context (C) Source: https://context7.com/stephane/libmodbus/llms.txt Creates a libmodbus context for TCP/IPv4 communication. It requires the server's IP address and port. The context must be freed using modbus_free(). Connection is established using modbus_connect(). ```c #include #include #include int main(void) { modbus_t *ctx; // Create a TCP context to connect to 192.168.1.100 on port 502 ctx = modbus_new_tcp("192.168.1.100", 502); if (ctx == NULL) { fprintf(stderr, "Unable to allocate libmodbus context\n"); return -1; } // For server mode, use NULL to listen on any address // ctx = modbus_new_tcp(NULL, 502); // Connect to the remote device if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } printf("Connected successfully!\n"); // ... perform operations ... modbus_close(ctx); modbus_free(ctx); return 0; } ``` -------------------------------- ### Perform Bit Manipulation with libmodbus Source: https://context7.com/stephane/libmodbus/llms.txt Demonstrates converting bytes to bit arrays and vice versa using libmodbus helper functions. These functions are essential for managing coil states and partial byte data in Modbus communications. ```c #include #include #include int main(void) { uint8_t bits[8]; uint8_t bytes[2]; uint8_t result_byte; memset(bits, 0, sizeof(bits)); modbus_set_bits_from_byte(bits, 0, 0xA5); printf("Byte 0xA5 as bits: "); for (int i = 0; i < 8; i++) { printf("%d", bits[i]); } printf("\n"); result_byte = modbus_get_byte_from_bits(bits, 0, 8); printf("Bits back to byte: 0x%02X\n", result_byte); bytes[0] = 0xFF; bytes[1] = 0x0F; memset(bits, 0, sizeof(bits)); modbus_set_bits_from_bytes(bits, 0, 16, bytes); printf("16 bits from 2 bytes: "); for (int i = 0; i < 16; i++) { printf("%d", bits[i]); } printf("\n"); result_byte = modbus_get_byte_from_bits(bits, 2, 5); printf("5 bits from index 2: 0x%02X\n", result_byte); return 0; } ``` -------------------------------- ### GET modbus_report_slave_id Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_report_slave_id.md Retrieves the slave ID, run status, and additional controller-specific data. ```APIDOC ## GET modbus_report_slave_id ### Description The modbus_report_slave_id() function sends a request to the controller to obtain a description, including the slave ID, run indicator status, and additional controller-specific data. ### Method C Function Call ### Endpoint modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest) ### Parameters #### Path Parameters - **ctx** (modbus_t*) - Required - The pointer to the libmodbus context. - **max_dest** (int) - Required - The maximum number of bytes to write to the destination buffer. - **dest** (uint8_t*) - Required - The buffer to store the response data. ### Request Example ```c uint8_t tab_bytes[MODBUS_MAX_PDU_LENGTH]; rc = modbus_report_slave_id(ctx, MODBUS_MAX_PDU_LENGTH, tab_bytes); ``` ### Response #### Success Response (int) - **return value** (int) - The number of bytes read. If the value is greater than max_dest, the response was truncated. #### Error Handling - Returns -1 on failure and sets errno. #### Response Example ```c // If rc > 1, tab_bytes[1] contains the run indicator status (0x00 = OFF, 0xFF = ON) printf("Run Status Indicator: %s\n", tab_bytes[1] ? "ON" : "OFF"); ``` ``` -------------------------------- ### Receive Modbus Confirmation (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Receives a Modbus confirmation (response or exception) after sending a raw request. This function is typically used in conjunction with `modbus_send_raw_request`. It requires the Modbus context and a buffer to store the received data. ```c #include modbus_t *ctx; uint8_t rcv_buf[128]; int rc; // ... after sending a raw request ... rc = modbus_receive_confirmation(ctx, rcv_buf); if (rc < 0) { // Handle error } else { // Process the received confirmation in rcv_buf } ``` -------------------------------- ### Create TCP Protocol Independent Modbus Context (C) Source: https://context7.com/stephane/libmodbus/llms.txt Creates a libmodbus context for TCP communication supporting both IPv4 and IPv6. It handles hostname resolution and is suitable for dual-stack networks. The context must be freed with modbus_free(). ```c #include #include #include int main(void) { modbus_t *ctx; // Connect to IPv6 localhost on port 502 ctx = modbus_new_tcp_pi("::1", "502"); if (ctx == NULL) { fprintf(stderr, "Unable to allocate libmodbus context\n"); return -1; } // Can also use hostname resolution // ctx = modbus_new_tcp_pi("modbus-server.local", "502"); // For server mode, use NULL to listen on any address // ctx = modbus_new_tcp_pi(NULL, "1502"); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } printf("Connected via TCP PI!\n"); modbus_close(ctx); modbus_free(ctx); return 0; } ``` -------------------------------- ### modbus_read_registers Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_read_registers.md Reads a specified number of holding registers from a Modbus device starting at a given address. The read values are stored in a provided destination array. ```APIDOC ## modbus_read_registers ### Description Reads the content of `nb` holding registers from the remote device, starting at address `addr`. The results are stored in the `dest` array as 16-bit word values. ### Method `int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```c modbus_t *ctx; uint16_t tab_reg[64]; int rc; int i; ctx = modbus_new_tcp("127.0.0.1", 502); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } rc = modbus_read_registers(ctx, 0, 10, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; } for (i=0; i < rc; i++) { printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]); } modbus_close(ctx); modbus_free(ctx); ``` ### Response #### Success Response (200) Returns the number of registers successfully read. The read values are stored in the `dest` array. #### Response Example `int` - Number of registers read (>= 0) #### Error Response - `-1`: An error occurred. `errno` is set to indicate the error. ### Errors - `EINVAL`: `ctx` or `dest` is NULL, or `nb` is less than 1. - `EMBXILVAL`: Too many registers requested (`nb` > `MODBUS_MAX_READ_REGISTERS`). ``` -------------------------------- ### Handle Modbus Errors and Exceptions Source: https://context7.com/stephane/libmodbus/llms.txt Demonstrates how to use modbus_strerror to retrieve human-readable error messages and handle specific Modbus exception codes using errno. ```c #include #include #include int main(void) { modbus_t *ctx; uint16_t regs[10]; int rc; ctx = modbus_new_tcp("192.168.1.100", 502); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection error: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } rc = modbus_read_registers(ctx, 99999, 5, regs); if (rc == -1) { switch (errno) { case EMBXILFUN: printf("Illegal function\n"); break; case EMBXILADD: printf("Illegal data address\n"); break; case EMBXILVAL: printf("Illegal data value\n"); break; case EMBXSFAIL: printf("Server device failure\n"); break; case EMBXSBUSY: printf("Server device busy\n"); break; case ETIMEDOUT: printf("Response timeout\n"); break; default: printf("Error: %s\n", modbus_strerror(errno)); } } modbus_close(ctx); modbus_free(ctx); return 0; } ``` -------------------------------- ### Set Int64 into Int16 Array (C Macro) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md A macro to set a 64-bit integer value into four consecutive 16-bit integers in an array. This is for preparing large integer data to be transmitted over Modbus. ```c #include uint16_t data_array[4]; int64_t value = 0x123456789ABCDEF0LL; MODBUS_SET_INT64_TO_INT16(data_array, 0, value); // data_array[0]=0x1234, data_array[1]=0x5678, data_array[2]=0x9ABC, data_array[3]=0xDEF0 ``` -------------------------------- ### Create RTU Modbus Context (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/modbus_new_rtu.md Allocates and initializes a modbus_t structure for RTU mode serial communication. Requires specifying the serial device, baud rate, parity, data bits, and stop bits. Returns a pointer to the modbus_t structure on success, or NULL on failure. ```c modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit); ``` ```c const int REMOTE_ID = 10; modbus_t *ctx; uint16_t tab_reg[10]; ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1); if (ctx == NULL) { fprintf(stderr, "Unable to create the libmodbus context\n"); return -1; } if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } modbus_set_slave(ctx, REMOTE_ID); // Read 2 registers from address 0 of server ID 10. modbus_read_registers(ctx, 0, 2, tab_reg); ``` -------------------------------- ### Read Modbus Registers (C) Source: https://github.com/stephane/libmodbus/blob/master/docs/index.md Reads a number of Modbus registers (16-bit integers) from a device. This function is used for reading holding registers. It requires the Modbus context, starting address, quantity, and a destination array for the register values. ```c #include modbus_t *ctx; uint16_t tab_rp_registers[128]; int rc; // ... connect and set slave ... // Read 5 registers starting from address 0 rc = modbus_read_registers(ctx, 0, 5, tab_rp_registers); if (rc < 0) { // Handle error } else { // Process the read registers in tab_rp_registers } ```