diff --git a/examples/server-handlers.h b/examples/server-handlers.h deleted file mode 100644 index 34fe927..0000000 --- a/examples/server-handlers.h +++ /dev/null @@ -1,63 +0,0 @@ -#include "modbusino.h" - -// Server (slave) handler functions - -// This server data model will support coils addresses 0 to 100 and registers addresses from 0 to 26 -#define COILS_ADDR_MAX 100 -#define REGS_ADDR_MAX 32 - -// A single mbsn_bitfield variable can keep 2000 coils -mbsn_bitfield server_coils = {0}; - -uint16_t server_registers[REGS_ADDR_MAX] = {0}; - - -mbsn_error handle_read_coils(uint16_t address, uint16_t quantity, mbsn_bitfield coils_out) { - if (address + quantity > COILS_ADDR_MAX + 1) - return MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS; - - // Read our coils values into coils_out - for (int i = 0; i < quantity; i++) { - bool value = mbsn_bitfield_read(server_coils, address + i); - mbsn_bitfield_write(coils_out, i, value); - } - - return MBSN_ERROR_NONE; -} - - -mbsn_error handle_write_multiple_coils(uint16_t address, uint16_t quantity, const mbsn_bitfield coils) { - if (address + quantity > COILS_ADDR_MAX + 1) - return MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS; - - // Write coils values to our server_coils - for (int i = 0; i < quantity; i++) { - mbsn_bitfield_write(server_coils, address + i, mbsn_bitfield_read(coils, i)); - } - - return MBSN_ERROR_NONE; -} - - -mbsn_error handler_read_holding_registers(uint16_t address, uint16_t quantity, uint16_t* registers_out) { - if (address + quantity > REGS_ADDR_MAX + 1) - return MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS; - - // Read our registers values into registers_out - for (int i = 0; i < quantity; i++) - registers_out[i] = server_registers[address + i]; - - return MBSN_ERROR_NONE; -} - - -mbsn_error handle_write_multiple_registers(uint16_t address, uint16_t quantity, const uint16_t* registers) { - if (address + quantity > REGS_ADDR_MAX + 1) - return MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS; - - // Write registers values to our server_registers - for (int i = 0; i < quantity; i++) - server_registers[address + i] = registers[i]; - - return MBSN_ERROR_NONE; -} diff --git a/examples/server-tcp.c b/examples/server-tcp.c index 59d7c2f..be68eb6 100644 --- a/examples/server-tcp.c +++ b/examples/server-tcp.c @@ -1,6 +1,5 @@ #include "modbusino.h" #include "platform.h" -#include "server-handlers.h" #include /* @@ -19,6 +18,66 @@ * The platform functions are for Linux systems. */ + +// The data model of this sever will support coils addresses 0 to 100 and registers addresses from 0 to 32 +#define COILS_ADDR_MAX 100 +#define REGS_ADDR_MAX 32 + +// A single mbsn_bitfield variable can keep 2000 coils +mbsn_bitfield server_coils = {0}; +uint16_t server_registers[REGS_ADDR_MAX] = {0}; + +mbsn_error handle_read_coils(uint16_t address, uint16_t quantity, mbsn_bitfield coils_out) { + if (address + quantity > COILS_ADDR_MAX + 1) + return MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS; + + // Read our coils values into coils_out + for (int i = 0; i < quantity; i++) { + bool value = mbsn_bitfield_read(server_coils, address + i); + mbsn_bitfield_write(coils_out, i, value); + } + + return MBSN_ERROR_NONE; +} + + +mbsn_error handle_write_multiple_coils(uint16_t address, uint16_t quantity, const mbsn_bitfield coils) { + if (address + quantity > COILS_ADDR_MAX + 1) + return MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS; + + // Write coils values to our server_coils + for (int i = 0; i < quantity; i++) { + mbsn_bitfield_write(server_coils, address + i, mbsn_bitfield_read(coils, i)); + } + + return MBSN_ERROR_NONE; +} + + +mbsn_error handler_read_holding_registers(uint16_t address, uint16_t quantity, uint16_t* registers_out) { + if (address + quantity > REGS_ADDR_MAX + 1) + return MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS; + + // Read our registers values into registers_out + for (int i = 0; i < quantity; i++) + registers_out[i] = server_registers[address + i]; + + return MBSN_ERROR_NONE; +} + + +mbsn_error handle_write_multiple_registers(uint16_t address, uint16_t quantity, const uint16_t* registers) { + if (address + quantity > REGS_ADDR_MAX + 1) + return MBSN_EXCEPTION_ILLEGAL_DATA_ADDRESS; + + // Write registers values to our server_registers + for (int i = 0; i < quantity; i++) + server_registers[address + i] = registers[i]; + + return MBSN_ERROR_NONE; +} + + int main(int argc, char* argv[]) { if (argc < 3) { fprintf(stderr, "Usage: server-tcp [address] [port]\n"); diff --git a/modbusino.c b/modbusino.c index 04d6659..27a8edf 100644 --- a/modbusino.c +++ b/modbusino.c @@ -5,6 +5,9 @@ #ifdef MBSN_DEBUG #include +#define DEBUG(...) printf(__VA_ARGS__) +#else +#define DEBUG(...) (void) (0) #endif #if !defined(MBSN_BIG_ENDIAN) && !defined(MBSN_LITTLE_ENDIAN) @@ -169,12 +172,6 @@ static mbsn_error recv(mbsn_t* mbsn, uint32_t count) { int ret = mbsn->platform.read_byte(mbsn->msg.buf + mbsn->msg.buf_idx + r, mbsn->byte_timeout_ms, mbsn->platform.arg); if (ret == 0) { -#ifdef MBSN_DEBUG - if (mbsn->address_rtu == 0) - printf("c: to\n"); - else - printf("s: to\n"); -#endif return MBSN_ERROR_TIMEOUT; } else if (ret != 1) { @@ -184,13 +181,6 @@ static mbsn_error recv(mbsn_t* mbsn, uint32_t count) { r++; } -#ifdef MBSN_DEBUG - if (mbsn->address_rtu == 0) - printf("c: recv %d\n", count); - else - printf("s: recv %d\n", count); -#endif - return MBSN_ERROR_NONE; } @@ -213,13 +203,6 @@ static mbsn_error send(mbsn_t* mbsn) { } } -#ifdef MBSN_DEBUG - if (mbsn->address_rtu == 0) - printf("c: sent %d\n", mbsn->msg.buf_idx - 1); - else - printf("s: sent %d\n", mbsn->msg.buf_idx - 1); -#endif - return MBSN_ERROR_NONE; } @@ -238,6 +221,8 @@ static mbsn_error recv_msg_footer(mbsn_t* mbsn) { return MBSN_ERROR_TRANSPORT; } + DEBUG("\n"); + return MBSN_ERROR_NONE; } @@ -357,14 +342,18 @@ static mbsn_error recv_res_header(mbsn_t* mbsn) { if (exception < 1 || exception > 4) return MBSN_ERROR_INVALID_RESPONSE; - else + else { + DEBUG("exception %d\n", exception); return exception; + } } else { return MBSN_ERROR_INVALID_RESPONSE; } } + DEBUG("MBSN res <- fc %d\t", mbsn->msg.fc); + return MBSN_ERROR_NONE; } @@ -393,15 +382,32 @@ static mbsn_error send_msg_footer(mbsn_t* mbsn) { } mbsn_error err = send(mbsn); + + DEBUG("\n"); + return err; } +static void send_req_header(mbsn_t* mbsn, uint16_t data_length) { + send_msg_header(mbsn, data_length); + DEBUG("MBSN req -> fc %d\t", mbsn->msg.fc); +} + + +static void send_res_header(mbsn_t* mbsn, uint16_t data_length) { + send_msg_header(mbsn, data_length); + DEBUG("MBSN res -> fc %d\t", mbsn->msg.fc); +} + + static mbsn_error handle_exception(mbsn_t* mbsn, uint8_t exception) { mbsn->msg.fc += 0x80; send_msg_header(mbsn, 1); put_1(mbsn, exception); + DEBUG("MBSN res -> exception %d\n", exception); + return send_msg_footer(mbsn); } @@ -414,6 +420,8 @@ static mbsn_error handle_read_discrete(mbsn_t* mbsn, mbsn_error (*callback)(uint uint16_t address = get_2(mbsn); uint16_t quantity = get_2(mbsn); + DEBUG("a %d\tq %d", address, quantity); + err = recv_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -437,12 +445,16 @@ static mbsn_error handle_read_discrete(mbsn_t* mbsn, mbsn_error (*callback)(uint if (!mbsn->msg.broadcast) { uint8_t discrete_bytes = (quantity / 8) + 1; - send_msg_header(mbsn, discrete_bytes); + send_res_header(mbsn, discrete_bytes); put_1(mbsn, discrete_bytes); + DEBUG("b %d\t", discrete_bytes); + + DEBUG("coils "); for (int i = 0; i < discrete_bytes; i++) { put_1(mbsn, bf[i]); + DEBUG("%d", bf[i]); } err = send_msg_footer(mbsn); @@ -467,6 +479,8 @@ static mbsn_error handle_read_registers(mbsn_t* mbsn, mbsn_error (*callback)(uin uint16_t address = get_2(mbsn); uint16_t quantity = get_2(mbsn); + DEBUG("a %d\tq %d", address, quantity); + err = recv_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -490,12 +504,16 @@ static mbsn_error handle_read_registers(mbsn_t* mbsn, mbsn_error (*callback)(uin if (!mbsn->msg.broadcast) { uint8_t regs_bytes = quantity * 2; - send_msg_header(mbsn, regs_bytes); + send_res_header(mbsn, regs_bytes); put_1(mbsn, regs_bytes); + DEBUG("b %d\t", regs_bytes); + + DEBUG("regs "); for (int i = 0; i < quantity; i++) { put_2(mbsn, regs[i]); + DEBUG("%d", regs[i]); } err = send_msg_footer(mbsn); @@ -540,6 +558,8 @@ static mbsn_error handle_write_single_coil(mbsn_t* mbsn) { uint16_t address = get_2(mbsn); uint16_t value = get_2(mbsn); + DEBUG("a %d\tvalue %d", address, value); + err = recv_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -558,9 +578,12 @@ static mbsn_error handle_write_single_coil(mbsn_t* mbsn) { } if (!mbsn->msg.broadcast) { - send_msg_header(mbsn, 4); + send_res_header(mbsn, 4); + put_2(mbsn, address); put_2(mbsn, value); + DEBUG("a %d\tvalue %d", address, value); + err = send_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -583,6 +606,8 @@ static mbsn_error handle_write_single_register(mbsn_t* mbsn) { uint16_t address = get_2(mbsn); uint16_t value = get_2(mbsn); + DEBUG("a %d\tvalue %d", address, value); + err = recv_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -598,9 +623,12 @@ static mbsn_error handle_write_single_register(mbsn_t* mbsn) { } if (!mbsn->msg.broadcast) { - send_msg_header(mbsn, 4); + send_res_header(mbsn, 4); + put_2(mbsn, address); put_2(mbsn, value); + DEBUG("a %d\tvalue %d", address, value); + err = send_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -624,6 +652,8 @@ static mbsn_error handle_write_multiple_coils(mbsn_t* mbsn) { uint16_t quantity = get_2(mbsn); uint8_t coils_bytes = get_1(mbsn); + DEBUG("a %d\tq %d\tb %d\tcoils ", address, quantity, coils_bytes); + err = recv(mbsn, coils_bytes); if (err != MBSN_ERROR_NONE) return err; @@ -631,6 +661,7 @@ static mbsn_error handle_write_multiple_coils(mbsn_t* mbsn) { mbsn_bitfield coils; for (int i = 0; i < coils_bytes; i++) { coils[i] = get_1(mbsn); + DEBUG("%d ", coils[i]); } err = recv_msg_footer(mbsn); @@ -660,9 +691,12 @@ static mbsn_error handle_write_multiple_coils(mbsn_t* mbsn) { } if (!mbsn->msg.broadcast) { - send_msg_header(mbsn, 4); + send_res_header(mbsn, 4); + put_2(mbsn, address); put_2(mbsn, quantity); + DEBUG("a %d\tq %d", address, quantity); + err = send_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -686,6 +720,8 @@ static mbsn_error handle_write_multiple_registers(mbsn_t* mbsn) { uint16_t quantity = get_2(mbsn); uint8_t registers_bytes = get_1(mbsn); + DEBUG("a %d\tq %d\tb %d\tregs ", address, quantity, registers_bytes); + err = recv(mbsn, registers_bytes); if (err != MBSN_ERROR_NONE) return err; @@ -693,6 +729,7 @@ static mbsn_error handle_write_multiple_registers(mbsn_t* mbsn) { uint16_t registers[0x007B]; for (int i = 0; i < registers_bytes / 2; i++) { registers[i] = get_2(mbsn); + DEBUG("%d ", registers[i]); } err = recv_msg_footer(mbsn); @@ -722,9 +759,12 @@ static mbsn_error handle_write_multiple_registers(mbsn_t* mbsn) { } if (!mbsn->msg.broadcast) { - send_msg_header(mbsn, 4); + send_res_header(mbsn, 4); + put_2(mbsn, address); put_2(mbsn, quantity); + DEBUG("a %d\tq %d", address, quantity); + err = send_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -740,6 +780,8 @@ static mbsn_error handle_write_multiple_registers(mbsn_t* mbsn) { static mbsn_error handle_req_fc(mbsn_t* mbsn) { + DEBUG("fc %d\t", mbsn->msg.fc); + mbsn_error err; switch (mbsn->msg.fc) { case 1: @@ -794,6 +836,16 @@ mbsn_error mbsn_server_poll(mbsn_t* mbsn) { return err; } +#ifdef MBSN_DEBUG + printf("MBSN req <- "); + if (mbsn->platform.transport == MBSN_TRANSPORT_RTU) { + if (mbsn->msg.broadcast) + printf("broadcast\t"); + + printf("client_id %d\t", mbsn->msg.unit_id); + } +#endif + err = handle_req_fc(mbsn); if (err != MBSN_ERROR_NONE) { if (!mbsn_error_is_exception(err)) @@ -812,11 +864,13 @@ static mbsn_error read_discrete(mbsn_t* mbsn, uint8_t fc, uint16_t address, uint return MBSN_ERROR_INVALID_ARGUMENT; msg_state_req(mbsn, fc); - send_msg_header(mbsn, 4); + send_req_header(mbsn, 4); put_2(mbsn, address); put_2(mbsn, quantity); + DEBUG("a %d\tq %d", address, quantity); + mbsn_error err = send_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -830,13 +884,16 @@ static mbsn_error read_discrete(mbsn_t* mbsn, uint8_t fc, uint16_t address, uint return err; uint8_t coils_bytes = get_1(mbsn); + DEBUG("b %d\t", coils_bytes); err = recv(mbsn, coils_bytes); if (err != MBSN_ERROR_NONE) return err; + DEBUG("coils "); for (int i = 0; i < coils_bytes; i++) { values[i] = get_1(mbsn); + DEBUG("%d", values[i]); } err = recv_msg_footer(mbsn); @@ -865,11 +922,13 @@ static mbsn_error read_registers(mbsn_t* mbsn, uint8_t fc, uint16_t address, uin return MBSN_ERROR_INVALID_ARGUMENT; msg_state_req(mbsn, fc); - send_msg_header(mbsn, 4); + send_req_header(mbsn, 4); put_2(mbsn, address); put_2(mbsn, quantity); + DEBUG("a %d\tq %d ", address, quantity); + mbsn_error err = send_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -883,13 +942,16 @@ static mbsn_error read_registers(mbsn_t* mbsn, uint8_t fc, uint16_t address, uin return err; uint8_t registers_bytes = get_1(mbsn); + DEBUG("b %d\t", registers_bytes); err = recv(mbsn, registers_bytes); if (err != MBSN_ERROR_NONE) return err; + DEBUG("regs "); for (int i = 0; i < registers_bytes / 2; i++) { registers[i] = get_2(mbsn); + DEBUG("%d", registers[i]); } err = recv_msg_footer(mbsn); @@ -915,13 +977,15 @@ mbsn_error mbsn_read_input_registers(mbsn_t* mbsn, uint16_t address, uint16_t qu mbsn_error mbsn_write_single_coil(mbsn_t* mbsn, uint16_t address, bool value) { msg_state_req(mbsn, 5); - send_msg_header(mbsn, 4); + send_req_header(mbsn, 4); uint16_t value_req = value ? 0xFF00 : 0; put_2(mbsn, address); put_2(mbsn, value_req); + DEBUG("a %d\tvalue %d ", address, value_req); + mbsn_error err = send_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -938,6 +1002,8 @@ mbsn_error mbsn_write_single_coil(mbsn_t* mbsn, uint16_t address, bool value) { uint16_t address_res = get_2(mbsn); uint16_t value_res = get_2(mbsn); + DEBUG("a %d\tvalue %d", address, value_res); + err = recv_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -955,11 +1021,13 @@ mbsn_error mbsn_write_single_coil(mbsn_t* mbsn, uint16_t address, bool value) { mbsn_error mbsn_write_single_register(mbsn_t* mbsn, uint16_t address, uint16_t value) { msg_state_req(mbsn, 6); - send_msg_header(mbsn, 4); + send_req_header(mbsn, 4); put_2(mbsn, address); put_2(mbsn, value); + DEBUG("a %d\tvalue %d", address, value); + mbsn_error err = send_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) return err; @@ -975,6 +1043,7 @@ mbsn_error mbsn_write_single_register(mbsn_t* mbsn, uint16_t address, uint16_t v uint16_t address_res = get_2(mbsn); uint16_t value_res = get_2(mbsn); + DEBUG("a %d\tvalue %d ", address, value_res); err = recv_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) @@ -1001,14 +1070,17 @@ mbsn_error mbsn_write_multiple_coils(mbsn_t* mbsn, uint16_t address, uint16_t qu uint8_t coils_bytes = (quantity / 8) + 1; msg_state_req(mbsn, 15); - send_msg_header(mbsn, 5 + coils_bytes); + send_req_header(mbsn, 5 + coils_bytes); put_2(mbsn, address); put_2(mbsn, quantity); put_1(mbsn, coils_bytes); + DEBUG("a %d\tq %d\tb %d\t", address, quantity, coils_bytes); + DEBUG("coils "); for (int i = 0; i < coils_bytes; i++) { put_1(mbsn, coils[i]); + DEBUG("%d ", coils[i]); } mbsn_error err = send_msg_footer(mbsn); @@ -1026,6 +1098,7 @@ mbsn_error mbsn_write_multiple_coils(mbsn_t* mbsn, uint16_t address, uint16_t qu uint16_t address_res = get_2(mbsn); uint16_t quantity_res = get_2(mbsn); + DEBUG("a %d\tq %d", address_res, quantity_res); err = recv_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) @@ -1052,14 +1125,17 @@ mbsn_error mbsn_write_multiple_registers(mbsn_t* mbsn, uint16_t address, uint16_ uint8_t registers_bytes = quantity * 2; msg_state_req(mbsn, 16); - send_msg_header(mbsn, 5 + registers_bytes); + send_req_header(mbsn, 5 + registers_bytes); put_2(mbsn, address); put_2(mbsn, quantity); put_1(mbsn, registers_bytes); + DEBUG("a %d\tq %d\tb %d\t", address, quantity, registers_bytes); + DEBUG("regs "); for (int i = 0; i < quantity; i++) { put_2(mbsn, registers[i]); + DEBUG("%d ", registers[i]); } mbsn_error err = send_msg_footer(mbsn); @@ -1077,6 +1153,7 @@ mbsn_error mbsn_write_multiple_registers(mbsn_t* mbsn, uint16_t address, uint16_ uint16_t address_res = get_2(mbsn); uint16_t quantity_res = get_2(mbsn); + DEBUG("a %d\tq %d", address_res, quantity_res); err = recv_msg_footer(mbsn); if (err != MBSN_ERROR_NONE) @@ -1096,8 +1173,11 @@ mbsn_error mbsn_write_multiple_registers(mbsn_t* mbsn, uint16_t address, uint16_ mbsn_error mbsn_send_raw_pdu(mbsn_t* mbsn, uint8_t fc, const void* data, uint32_t data_len) { msg_state_req(mbsn, fc); send_msg_header(mbsn, data_len); + + DEBUG("raw "); for (uint32_t i = 0; i < data_len; i++) { put_1(mbsn, ((uint8_t*) (data))[i]); + DEBUG("%d ", ((uint8_t*) (data))[i]); } return send_msg_footer(mbsn); diff --git a/modbusino_platform.h b/modbusino_platform.h deleted file mode 100644 index bc0b05d..0000000 --- a/modbusino_platform.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef MODBUSINO_MODBUSINO_PLATFORM_H -#define MODBUSINO_MODBUSINO_PLATFORM_H - -#include -#include - -/* ### Endianness macros. - * In most cases, endianness will be detected automatically, so they can be left commented -*/ -/* Uncomment if your platform is big endian */ -// #define MBSN_BIG_ENDIAN - -/* Uncomment if your platform is little endian */ -// #define MBSN_LITTLE_ENDIAN - - -/* ### Transport function pointers. - * Point them to your platform-specific methods that read/write data to/from a serial port or a TCP connection and - * flush their receive buffers. - * - * read()/write() methods should block until the requested byte is read/written. - * If your implementation uses a read/write timeout, and the timeout expires, the methods should return 0. - * Their return values should be: - * - 1 in case of success - * - 0 if no data is available immediately or after an internal timeout expiration - * - -1 in case of error - * - * The primary effect of flush() methods should be the flushing of the underlying receive buffer. - * These methods will be called in case of error, in order to "reset" the state of the connection. - * On most platforms - * - * You can leave some of them NULL if you don't plan to use a certain transport. - */ -int (*mbsn_rtu_flush)() = NULL; - -int (*mbsn_rtu_read_byte)(uint8_t* b) = NULL; - -int (*mbsn_rtu_write_byte)(uint8_t b) = NULL; - -int (*mbsn_tcp_flush)() = NULL; - -int (*mbsn_tcp_read_byte)(uint8_t* b) = NULL; - -int (*mbsn_tcp_write_byte)(uint8_t b) = NULL; - - -#endif //MODBUSINO_MODBUSINO_PLATFORM_H