Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ add_library(nanomodbus nanomodbus.c)
target_include_directories(nanomodbus PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

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)
if(!WIN32)
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()
endif ()

if (BUILD_TESTS)
Expand All @@ -33,6 +35,10 @@ if (BUILD_TESTS)
target_compile_definitions(multi_server_rtu PUBLIC NMBS_DEBUG)
target_link_libraries(multi_server_rtu pthread)

if(WIN32)
target_link_libraries(nanomodbus_tests ws2_32 )
endif()

enable_testing()
add_test(NAME test_general COMMAND $<TARGET_FILE:nanomodbus_tests>)
add_test(NAME test_server_disabled COMMAND $<TARGET_FILE:server_disabled>)
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Its main features are:
- 21 (0x15) Write File Record
- 23 (0x17) Read/Write Multiple registers
- 43/14 (0x2B/0x0E) Read Device Identification
- 24 (0x18) Read Fifo Queue
- Platform-agnostic
- Requires only C99 and its standard library
- Data transport read/write functions are implemented by the user
Expand Down Expand Up @@ -198,6 +199,7 @@ examples.
- `NMBS_SERVER_WRITE_FILE_RECORD_DISABLED`
- `NMBS_SERVER_READ_WRITE_REGISTERS_DISABLED`
- `NMBS_SERVER_READ_DEVICE_IDENTIFICATION_DISABLED`
- `NMBS_SERVER_READ_FIFO_QUEUE`
- `NMBS_STRERROR_DISABLED` to disable the code that converts `nmbs_error`s to strings
- `NMBS_BITFIELD_MAX` to set the size of the `nmbs_bitfield` type, used to store coil values (
default is `2000`)
Expand Down
125 changes: 125 additions & 0 deletions nanomodbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,39 @@ nmbs_error recv_read_device_identification_res(nmbs_t* nmbs, uint8_t buffers_cou
return recv_msg_footer(nmbs);
}

nmbs_error recv_read_fifo_queue_registers(nmbs_t* nmbs, uint16_t* quantity, uint16_t* registers) {
nmbs_error err = recv_res_header(nmbs);
if (err != NMBS_ERROR_NONE)
return err;

err = recv(nmbs, 2);
if (err != NMBS_ERROR_NONE)
return err;

const uint8_t registers_bytes = get_2(nmbs);
NMBS_DEBUG_PRINT("b %d\t", registers_bytes);

if (registers_bytes > 62)
return NMBS_ERROR_INVALID_RESPONSE;

err = recv(nmbs, registers_bytes);
if (err != NMBS_ERROR_NONE)
return err;

NMBS_DEBUG_PRINT("regs ");
for (int i = 0; i < registers_bytes / 2; i++) {
uint16_t reg = get_2(nmbs);
if (registers)
registers[i] = reg;
NMBS_DEBUG_PRINT("%d ", reg);
}
err = recv_msg_footer(nmbs);
if (err != NMBS_ERROR_NONE)
return err;

*quantity = registers_bytes / 2;
return NMBS_ERROR_NONE;
}

#ifndef NMBS_SERVER_DISABLED
#if !defined(NMBS_SERVER_READ_COILS_DISABLED) || !defined(NMBS_SERVER_READ_DISCRETE_INPUTS_DISABLED)
Expand Down Expand Up @@ -1805,6 +1838,71 @@ static nmbs_error handle_read_device_identification(nmbs_t* nmbs) {
}
#endif

#ifndef NMBS_SERVER_READ_FIFO_QUEUE
static nmbs_error handle_read_fifo_queue(nmbs_t* nmbs) {

nmbs_error err = recv(nmbs, 2);
if (err != NMBS_ERROR_NONE)
return err;


const int32_t fifo_pointer_address = get_2(nmbs);


NMBS_DEBUG_PRINT("a %d\tq 0", fifo_pointer_address);

err = recv_msg_footer(nmbs);
if (err != NMBS_ERROR_NONE)
return err;

if (!nmbs->msg.ignored) {
// trange condition check
// MODBUS Application Protocol Specification
if ((fifo_pointer_address < 0) || (fifo_pointer_address > 65535))
return send_exception_msg(nmbs, NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS);

if (nmbs->callbacks.read_fifo) {
uint16_t regs[32] = {0};
uint16_t fifo_sz = 0;
err = nmbs->callbacks.read_fifo((uint16_t) fifo_pointer_address, regs, &fifo_sz, nmbs->msg.unit_id,
nmbs->callbacks.arg);
if (err != NMBS_ERROR_NONE) {
if (nmbs_error_is_exception(err))
return send_exception_msg(nmbs, err);

return send_exception_msg(nmbs, NMBS_EXCEPTION_SERVER_DEVICE_FAILURE);
}

if (!nmbs->msg.broadcast) {
const uint8_t regs_bytes = fifo_sz * 2;
put_res_header(nmbs, 2 + regs_bytes);

put_2(nmbs, regs_bytes);

NMBS_DEBUG_PRINT("b %d\t", regs_bytes);

NMBS_DEBUG_PRINT("regs ");
for (int i = 0; i < fifo_sz; i++) {
put_2(nmbs, regs[i]);
NMBS_DEBUG_PRINT("%d ", regs[i]);
}

err = send_msg(nmbs);
if (err != NMBS_ERROR_NONE)
return err;
}
}
else {
return send_exception_msg(nmbs, NMBS_EXCEPTION_ILLEGAL_FUNCTION);
}
}
else {
//return recv_read_registers_res(nmbs, quantity, NULL);
}

return NMBS_ERROR_NONE;
}
#endif

static nmbs_error handle_req_fc(nmbs_t* nmbs) {
NMBS_DEBUG_PRINT("fc %d\t", nmbs->msg.fc);
Expand Down Expand Up @@ -1882,6 +1980,13 @@ static nmbs_error handle_req_fc(nmbs_t* nmbs) {
err = handle_read_device_identification(nmbs);
break;
#endif

#ifndef NMBS_SERVER_READ_FIFO_QUEUE_DISABLED
case 24:
err = handle_read_fifo_queue(nmbs);
break;
#endif

default:
nmbs->platform.flush(nmbs, nmbs->platform.arg);
if (!nmbs->msg.ignored)
Expand Down Expand Up @@ -2411,6 +2516,26 @@ nmbs_error nmbs_receive_raw_pdu_response(nmbs_t* nmbs, uint8_t* data_out, uint8_

return NMBS_ERROR_NONE;
}

nmbs_error nmbs_read_fifo_queue(nmbs_t* nmbs, uint16_t address, uint16_t* read_quantity, uint16_t* registers_out) {


// if ((uint32_t) address > ((uint32_t) 0xFFFF))
// return NMBS_ERROR_INVALID_ARGUMENT;

msg_state_req(nmbs, 24);
put_req_header(nmbs, 2);

put_2(nmbs, address);

NMBS_DEBUG_PRINT("a %d\tq %d ", address, 0);

const nmbs_error err = send_msg(nmbs);
if (err != NMBS_ERROR_NONE)
return err;

return recv_read_fifo_queue_registers(nmbs, read_quantity, registers_out);
}
#endif


Expand Down
17 changes: 17 additions & 0 deletions nanomodbus.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ typedef struct nmbs_callbacks {
#endif
#endif

#ifndef NMBS_SERVER_READ_FIFO_QUEUE
nmbs_error (*read_fifo_sz)(uint16_t address);
nmbs_error (*read_fifo)(uint16_t address, uint16_t* registers_out, uint16_t* fifo_size, uint8_t unit_id, void* arg);
#endif

void* arg; // User data, will be passed to functions above
uint32_t initialized; // Reserved, workaround for older user code not calling nmbs_callbacks_create()
} nmbs_callbacks;
Expand Down Expand Up @@ -536,6 +541,17 @@ nmbs_error nmbs_send_raw_pdu(nmbs_t* nmbs, uint8_t fc, const uint8_t* data, uint
* @return NMBS_ERROR_NONE if successful, other errors otherwise.
*/
nmbs_error nmbs_receive_raw_pdu_response(nmbs_t* nmbs, uint8_t* data_out, uint8_t data_out_len);

/* Send a FC 24 (0x18) Read fifo queues
* @param nmbs pointer to the nmbs_t instance
* @param address starting address
* @param quantity quantity of read registers
* @param registers_out array where the registers will be stored
*
* @return NMBS_ERROR_NONE if successful, other errors otherwise.
*/

nmbs_error nmbs_read_fifo_queue(nmbs_t* nmbs, uint16_t address, uint16_t* read_quantity, uint16_t* registers_out);
#endif

/** Calculate the Modbus CRC of some data.
Expand All @@ -554,6 +570,7 @@ uint16_t nmbs_crc_calc(const uint8_t* data, uint32_t length, void* arg);
const char* nmbs_strerror(nmbs_error error);
#endif


#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
13 changes: 13 additions & 0 deletions tests/multi_server_rtu.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#ifdef _WIN32
#include <windows.h>
typedef SOCKET socket_t;
#else
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#endif

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down
Loading