35#define NMBS_DEBUG_PRINT(...) printf(__VA_ARGS__)
37#define NMBS_DEBUG_PRINT(...) (void) (0)
41static uint8_t get_1(
nmbs_t* nmbs) {
48static void put_1(
nmbs_t* nmbs, uint8_t data) {
54static void discard_1(
nmbs_t* nmbs) {
59#ifndef NMBS_SERVER_DISABLED
60static void discard_n(
nmbs_t* nmbs, uint16_t n) {
66static uint16_t get_2(
nmbs_t* nmbs) {
69 nmbs->msg.buf_idx += 2;
74static void put_2(
nmbs_t* nmbs, uint16_t data) {
81#ifndef NMBS_SERVER_DISABLED
82static void set_1(
nmbs_t* nmbs, uint8_t data, uint8_t index) {
83 nmbs->
msg.
buf[index] = data;
87static void set_2(
nmbs_t* nmbs, uint16_t data, uint8_t index) {
88 nmbs->
msg.
buf[index] = (uint8_t) ((data >> 8) & 0xFFU);
89 nmbs->
msg.
buf[index + 1] = (uint8_t) data;
94static uint8_t* get_n(
nmbs_t* nmbs, uint16_t n) {
101#ifndef NMBS_SERVER_DISABLED
102static void put_n(
nmbs_t* nmbs,
const uint8_t* data, uint8_t size) {
108static uint16_t* get_regs(
nmbs_t* nmbs, uint16_t n) {
112 msg_buf_ptr[n] = (msg_buf_ptr[n] << 8) | ((msg_buf_ptr[n] >> 8) & 0xFF);
119#ifndef NMBS_CLIENT_DISABLED
120static void put_regs(
nmbs_t* nmbs,
const uint16_t* data, uint16_t n) {
124 msg_buf_ptr[n] = (data[n] << 8) | ((data[n] >> 8) & 0xFF);
130static void swap_regs(uint16_t* data, uint16_t n) {
132 data[n] = (data[n] << 8) | ((data[n] >> 8) & 0xFF);
137static void msg_buf_reset(
nmbs_t* nmbs) {
142static void msg_state_reset(
nmbs_t* nmbs) {
152#ifndef NMBS_CLIENT_DISABLED
153static void msg_state_req(
nmbs_t* nmbs, uint8_t fc) {
162 msg_state_reset(nmbs);
176 memset(nmbs, 0,
sizeof(
nmbs_t));
187 if (!platform_conf->
read || !platform_conf->
write)
217 uint16_t crc = 0xFFFF;
218 for (uint32_t i = 0; i < length; i++) {
219 crc ^= (uint16_t) data[i];
220 for (
int j = 8; j != 0; j--) {
221 if ((crc & 0x0001) != 0) {
230 return (uint16_t) (crc << 8) | (uint16_t) (crc >> 8);
279 uint16_t recv_crc = get_2(nmbs);
294 msg_state_reset(nmbs);
296 *first_byte_received =
false;
306 *first_byte_received =
true;
314 nmbs->
msg.
fc = get_1(nmbs);
324 *first_byte_received =
true;
337 uint16_t protocol_id = get_2(nmbs);
338 uint16_t length = get_2(nmbs);
340 nmbs->
msg.
fc = get_1(nmbs);
342 if (protocol_id != 0)
353static void put_msg_header(
nmbs_t* nmbs, uint16_t data_length) {
362 put_2(nmbs, (uint16_t) (1 + 1 + data_length));
366 put_1(nmbs, nmbs->
msg.
fc);
370#ifndef NMBS_SERVER_DISABLED
371static void set_msg_header_size(
nmbs_t* nmbs, uint16_t data_length) {
374 set_2(nmbs, data_length, 4);
394#ifndef NMBS_SERVER_DISABLED
396 nmbs_error err = recv_msg_header(nmbs, first_byte_received);
402 if (nmbs->
msg.
unit_id == NMBS_BROADCAST_ADDRESS)
414static void put_res_header(
nmbs_t* nmbs, uint16_t data_length) {
415 put_msg_header(nmbs, data_length);
421 nmbs->
msg.
fc += 0x80;
422 put_msg_header(nmbs, 1);
423 put_1(nmbs, exception);
427 return send_msg(nmbs);
435 uint8_t req_fc = nmbs->
msg.
fc;
437 bool first_byte_received =
false;
438 nmbs_error err = recv_msg_header(nmbs, &first_byte_received);
450 if (nmbs->
msg.
fc != req_fc) {
451 if (nmbs->
msg.
fc - 0x80 == req_fc) {
456 uint8_t exception = get_1(nmbs);
457 err = recv_msg_footer(nmbs);
461 if (exception < 1 || exception > 4)
478#ifndef NMBS_CLIENT_DISABLED
479static void put_req_header(
nmbs_t* nmbs, uint16_t data_length) {
480 put_msg_header(nmbs, data_length);
483 printf(
"NMBS req -> ");
486 printf(
"broadcast\t");
491 printf(
"fc %d\t", nmbs->
msg.
fc);
506 uint8_t coils_bytes = get_1(nmbs);
509 if (coils_bytes > 250) {
513 err = recv(nmbs, coils_bytes);
518 for (
int i = 0; i < coils_bytes; i++) {
519 uint8_t coil = get_1(nmbs);
525 err = recv_msg_footer(nmbs);
533static nmbs_error recv_read_registers_res(
nmbs_t* nmbs, uint16_t quantity, uint16_t* registers) {
542 uint8_t registers_bytes = get_1(nmbs);
545 if (registers_bytes > 250)
548 err = recv(nmbs, registers_bytes);
553 for (
int i = 0; i < registers_bytes / 2; i++) {
554 uint16_t reg = get_2(nmbs);
560 err = recv_msg_footer(nmbs);
564 if (registers_bytes != quantity * 2)
580 uint16_t address_res = get_2(nmbs);
581 uint16_t value_res = get_2(nmbs);
585 err = recv_msg_footer(nmbs);
589 if (address_res != address)
592 if (value_res != value_req)
608 uint16_t address_res = get_2(nmbs);
609 uint16_t value_res = get_2(nmbs);
612 err = recv_msg_footer(nmbs);
616 if (address_res != address)
619 if (value_res != value_req)
635 uint16_t address_res = get_2(nmbs);
636 uint16_t quantity_res = get_2(nmbs);
639 err = recv_msg_footer(nmbs);
643 if (address_res != address)
646 if (quantity_res != quantity)
662 uint16_t address_res = get_2(nmbs);
663 uint16_t quantity_res = get_2(nmbs);
666 err = recv_msg_footer(nmbs);
670 if (address_res != address)
673 if (quantity_res != quantity)
689 uint8_t response_size = get_1(nmbs);
690 if (response_size > 250) {
694 err = recv(nmbs, response_size);
698 uint8_t subreq_data_size = get_1(nmbs) - 1;
699 uint8_t subreq_reference_type = get_1(nmbs);
700 uint16_t* subreq_record_data = (uint16_t*) get_n(nmbs, subreq_data_size);
702 err = recv_msg_footer(nmbs);
707 if (subreq_reference_type != 6)
710 if (count != (subreq_data_size / 2))
713 swap_regs(subreq_record_data, subreq_data_size / 2);
714 memcpy(registers, subreq_record_data, subreq_data_size);
722 const uint16_t* registers, uint16_t count) {
731 uint8_t response_size = get_1(nmbs);
732 if (response_size > 251)
735 err = recv(nmbs, response_size);
739 uint8_t subreq_reference_type = get_1(nmbs);
740 uint16_t subreq_file_number = get_2(nmbs);
741 uint16_t subreq_record_number = get_2(nmbs);
742 uint16_t subreq_record_length = get_2(nmbs);
743 NMBS_DEBUG_PRINT(
"a %d\tr %d\tl %d\t fwrite ", subreq_file_number, subreq_record_number, subreq_record_length);
745 uint16_t subreq_data_size = subreq_record_length * 2;
746 uint16_t* subreq_record_data = (uint16_t*) get_n(nmbs, subreq_data_size);
748 err = recv_msg_footer(nmbs);
753 if (subreq_reference_type != 6)
756 if (subreq_file_number != file_number)
759 if (subreq_record_number != record_number)
762 if (subreq_record_length != count)
765 swap_regs(subreq_record_data, subreq_record_length);
766 if (memcmp(registers, subreq_record_data, subreq_data_size) != 0)
774 uint8_t buffers_length,
const uint8_t* order, uint8_t* ids_out,
775 uint8_t* next_object_id_out, uint8_t* objects_count_out) {
784 uint8_t mei_type = get_1(nmbs);
785 if (mei_type != 0x0E)
788 uint8_t read_device_id_code = get_1(nmbs);
789 if (read_device_id_code < 1 || read_device_id_code > 4)
792 uint8_t conformity_level = get_1(nmbs);
793 if (conformity_level < 1 || (conformity_level > 3 && conformity_level < 0x81) || conformity_level > 0x83)
796 uint8_t more_follows = get_1(nmbs);
797 if (more_follows != 0 && more_follows != 0xFF)
800 uint8_t next_object_id = get_1(nmbs);
802 uint8_t objects_count = get_1(nmbs);
803 if (objects_count_out)
804 *objects_count_out = objects_count;
806 if (buffers_count == 0) {
809 else if (objects_count > buffers_count)
812 if (more_follows == 0)
813 next_object_id = 0x7F;
815 if (next_object_id_out)
816 *next_object_id_out = next_object_id;
818 uint8_t res_size_left = 253 - 7;
819 for (
int i = 0; i < objects_count; i++) {
824 uint8_t object_id = get_1(nmbs);
825 uint8_t object_length = get_1(nmbs);
828 if (object_length > res_size_left)
831 err = recv(nmbs, object_length);
835 const char* str = (
const char*) get_n(nmbs, object_length);
838 ids_out[i] = object_id;
840 uint8_t buf_index = i;
842 buf_index = order[object_id];
844 strncpy(buffers_out[buf_index], str, buffers_length);
845 buffers_out[buf_index][object_length] = 0;
849 return recv_msg_footer(nmbs);
853#ifndef NMBS_SERVER_DISABLED
854#if !defined(NMBS_SERVER_READ_COILS_DISABLED) || !defined(NMBS_SERVER_READ_DISCRETE_INPUTS_DISABLED)
861 uint16_t address = get_2(nmbs);
862 uint16_t quantity = get_2(nmbs);
866 err = recv_msg_footer(nmbs);
871 if (quantity < 1 || quantity > 2000)
874 if ((uint32_t) address + (uint32_t) quantity > ((uint32_t) 0xFFFF) + 1)
882 return send_exception_msg(nmbs, err);
888 uint8_t discrete_bytes = (quantity + 7) / 8;
889 put_res_header(nmbs, 1 + discrete_bytes);
891 put_1(nmbs, discrete_bytes);
896 for (
int i = 0; i < discrete_bytes; i++) {
897 put_1(nmbs, bitfield[i]);
901 err = send_msg(nmbs);
911 return recv_read_discrete_res(nmbs, NULL);
919#if !defined(NMBS_SERVER_READ_HOLDING_REGISTERS_DISABLED) || !defined(NMBS_SERVER_READ_INPUT_REGISTERS_DISABLED)
921 nmbs_error (*callback)(uint16_t, uint16_t, uint16_t*, uint8_t,
void*)) {
926 uint16_t address = get_2(nmbs);
927 uint16_t quantity = get_2(nmbs);
931 err = recv_msg_footer(nmbs);
936 if (quantity < 1 || quantity > 125)
939 if ((uint32_t) address + (uint32_t) quantity > ((uint32_t) 0xFFFF) + 1)
943 uint16_t regs[125] = {0};
947 return send_exception_msg(nmbs, err);
954 uint8_t regs_bytes = quantity * 2;
955 put_res_header(nmbs, 1 + regs_bytes);
957 put_1(nmbs, regs_bytes);
962 for (
int i = 0; i < quantity; i++) {
963 put_2(nmbs, regs[i]);
967 err = send_msg(nmbs);
977 return recv_read_registers_res(nmbs, quantity, NULL);
985#ifndef NMBS_SERVER_READ_COILS_DISABLED
992#ifndef NMBS_SERVER_READ_DISCRETE_INPUTS_DISABLED
999#ifndef NMBS_SERVER_READ_HOLDING_REGISTERS_DISABLED
1006#ifndef NMBS_SERVER_READ_INPUT_REGISTERS_DISABLED
1013#ifndef NMBS_SERVER_WRITE_SINGLE_COIL_DISABLED
1019 uint16_t address = get_2(nmbs);
1020 uint16_t value = get_2(nmbs);
1024 err = recv_msg_footer(nmbs);
1030 if (value != 0 && value != 0xFF00)
1034 nmbs->callbacks.arg);
1037 return send_exception_msg(nmbs, err);
1043 put_res_header(nmbs, 4);
1045 put_2(nmbs, address);
1049 err = send_msg(nmbs);
1067#ifndef NMBS_SERVER_WRITE_SINGLE_REGISTER_DISABLED
1073 uint16_t address = get_2(nmbs);
1074 uint16_t value = get_2(nmbs);
1078 err = recv_msg_footer(nmbs);
1087 return send_exception_msg(nmbs, err);
1093 put_res_header(nmbs, 4);
1095 put_2(nmbs, address);
1099 err = send_msg(nmbs);
1117#ifndef NMBS_SERVER_WRITE_MULTIPLE_COILS_DISABLED
1123 uint16_t address = get_2(nmbs);
1124 uint16_t quantity = get_2(nmbs);
1125 uint8_t coils_bytes = get_1(nmbs);
1127 NMBS_DEBUG_PRINT(
"a %d\tq %d\tb %d\tcoils ", address, quantity, coils_bytes);
1129 if (coils_bytes > 246)
1132 err = recv(nmbs, coils_bytes);
1137 for (
int i = 0; i < coils_bytes; i++) {
1138 coils[i] = get_1(nmbs);
1142 err = recv_msg_footer(nmbs);
1147 if (quantity < 1 || quantity > 0x07B0)
1150 if ((uint32_t) address + (uint32_t) quantity > ((uint32_t) 0xFFFF) + 1)
1153 if (coils_bytes == 0)
1156 if ((quantity + 7) / 8 != coils_bytes)
1164 return send_exception_msg(nmbs, err);
1170 put_res_header(nmbs, 4);
1172 put_2(nmbs, address);
1173 put_2(nmbs, quantity);
1176 err = send_msg(nmbs);
1194#ifndef NMBS_SERVER_WRITE_MULTIPLE_REGISTERS_DISABLED
1200 uint16_t address = get_2(nmbs);
1201 uint16_t quantity = get_2(nmbs);
1202 uint8_t registers_bytes = get_1(nmbs);
1204 NMBS_DEBUG_PRINT(
"a %d\tq %d\tb %d\tregs ", address, quantity, registers_bytes);
1206 err = recv(nmbs, registers_bytes);
1210 if (registers_bytes > 246)
1213 uint16_t registers[0x007B];
1214 for (
int i = 0; i < registers_bytes / 2; i++) {
1215 registers[i] = get_2(nmbs);
1219 err = recv_msg_footer(nmbs);
1224 if (quantity < 1 || quantity > 0x007B)
1227 if ((uint32_t) address + (uint32_t) quantity > ((uint32_t) 0xFFFF) + 1)
1230 if (registers_bytes == 0)
1233 if (registers_bytes != quantity * 2)
1241 return send_exception_msg(nmbs, err);
1247 put_res_header(nmbs, 4);
1249 put_2(nmbs, address);
1250 put_2(nmbs, quantity);
1253 err = send_msg(nmbs);
1270#ifndef NMBS_SERVER_READ_FILE_RECORD_DISABLED
1276 uint8_t request_size = get_1(nmbs);
1277 if (request_size > 245)
1280 err = recv(nmbs, request_size);
1284 const uint8_t subreq_header_size = 7;
1285 const uint8_t subreq_count = request_size / subreq_header_size;
1288 uint8_t reference_type;
1289 uint16_t file_number;
1290 uint16_t record_number;
1291 uint16_t record_length;
1293#ifdef __STDC_NO_VLA__
1296 subreq[subreq_count];
1299 uint8_t response_data_size = 0;
1301 for (uint8_t i = 0; i < subreq_count; i++) {
1302 subreq[i].reference_type = get_1(nmbs);
1303 subreq[i].file_number = get_2(nmbs);
1304 subreq[i].record_number = get_2(nmbs);
1305 subreq[i].record_length = get_2(nmbs);
1307 response_data_size += 2 + subreq[i].record_length * 2;
1310 discard_n(nmbs, request_size % subreq_header_size);
1312 err = recv_msg_footer(nmbs);
1317 if (request_size % subreq_header_size)
1320 if (request_size < 0x07 || request_size > 0xF5)
1323 for (uint8_t i = 0; i < subreq_count; i++) {
1324 if (subreq[i].reference_type != 0x06)
1327 if (subreq[i].file_number == 0x0000)
1330 if (subreq[i].record_number > 0x270F)
1333 if (subreq[i].record_length > 124)
1336 NMBS_DEBUG_PRINT(
"a %d\tr %d\tl %d\t fread ", subreq[i].file_number, subreq[i].record_number,
1337 subreq[i].record_length);
1340 put_res_header(nmbs, response_data_size);
1341 put_1(nmbs, response_data_size);
1344 for (uint8_t i = 0; i < subreq_count; i++) {
1345 uint16_t subreq_data_size = subreq[i].record_length * 2;
1346 put_1(nmbs, subreq_data_size + 1);
1348 uint16_t* subreq_data = (uint16_t*) get_n(nmbs, subreq_data_size);
1354 return send_exception_msg(nmbs, err);
1359 swap_regs(subreq_data, subreq[i].record_length);
1367 err = send_msg(nmbs);
1380#ifndef NMBS_SERVER_WRITE_FILE_RECORD_DISABLED
1386 uint8_t request_size = get_1(nmbs);
1387 if (request_size > 251) {
1391 err = recv(nmbs, request_size);
1397 discard_n(nmbs, request_size);
1399 err = recv_msg_footer(nmbs);
1404 const uint8_t subreq_header_size = 7;
1405 uint16_t size = request_size;
1408 if (request_size < 0x07 || request_size > 0xFB)
1412 uint8_t subreq_reference_type = get_1(nmbs);
1413 uint16_t subreq_file_number_c = get_2(nmbs);
1414 uint16_t subreq_record_number_c = get_2(nmbs);
1415 uint16_t subreq_record_length_c = get_2(nmbs);
1416 discard_n(nmbs, subreq_record_length_c * 2);
1418 if (subreq_reference_type != 0x06)
1421 if (subreq_file_number_c == 0x0000)
1424 if (subreq_record_number_c > 0x270F)
1427 if (subreq_record_length_c > 122)
1430 NMBS_DEBUG_PRINT(
"a %d\tr %d\tl %d\t fwrite ", subreq_file_number_c, subreq_record_number_c,
1431 subreq_record_length_c);
1432 size -= (subreq_header_size + subreq_record_length_c * 2);
1433 }
while (size >= subreq_header_size);
1440 size = request_size;
1445 uint16_t subreq_file_number = get_2(nmbs);
1446 uint16_t subreq_record_number = get_2(nmbs);
1447 uint16_t subreq_record_length = get_2(nmbs);
1448 uint16_t* subreq_data = get_regs(nmbs, subreq_record_length);
1455 return send_exception_msg(nmbs, err);
1460 swap_regs(subreq_data, subreq_record_length);
1466 size -= (subreq_header_size + subreq_record_length * 2);
1467 }
while (size >= subreq_header_size);
1473 discard_n(nmbs, request_size);
1475 err = send_msg(nmbs);
1488#ifndef NMBS_SERVER_READ_WRITE_REGISTERS_DISABLED
1494 uint16_t read_address = get_2(nmbs);
1495 uint16_t read_quantity = get_2(nmbs);
1496 uint16_t write_address = get_2(nmbs);
1497 uint16_t write_quantity = get_2(nmbs);
1499 uint8_t byte_count_write = get_1(nmbs);
1501 NMBS_DEBUG_PRINT(
"ra %d\trq %d\t wa %d\t wq %d\t b %d\tregs ", read_address, read_quantity, write_address,
1502 write_quantity, byte_count_write);
1504 if (byte_count_write > 242)
1507 err = recv(nmbs, byte_count_write);
1511#ifdef __STDC_NO_VLA__
1512 uint16_t registers[0x007B];
1514 uint16_t registers[byte_count_write / 2];
1516 for (
int i = 0; i < byte_count_write / 2; i++) {
1517 registers[i] = get_2(nmbs);
1521 err = recv_msg_footer(nmbs);
1526 if (read_quantity < 1 || read_quantity > 0x007D)
1529 if (write_quantity < 1 || write_quantity > 0x007B)
1532 if (byte_count_write != write_quantity * 2)
1535 if ((uint32_t) read_address + (uint32_t) read_quantity > ((uint32_t) 0xFFFF) + 1)
1538 if ((uint32_t) write_address + (uint32_t) write_quantity > ((uint32_t) 0xFFFF) + 1)
1548 return send_exception_msg(nmbs, err);
1554#ifdef __STDC_NO_VLA__
1557 uint16_t regs[read_quantity];
1563 return send_exception_msg(nmbs, err);
1568 uint8_t regs_bytes = read_quantity * 2;
1569 put_res_header(nmbs, 1 + regs_bytes);
1571 put_1(nmbs, regs_bytes);
1576 for (
int i = 0; i < read_quantity; i++) {
1577 put_2(nmbs, regs[i]);
1581 err = send_msg(nmbs);
1594#ifndef NMBS_SERVER_READ_DEVICE_IDENTIFICATION_DISABLED
1600 uint8_t mei_type = get_1(nmbs);
1601 uint8_t read_device_id_code = get_1(nmbs);
1602 uint8_t object_id = get_1(nmbs);
1606 err = recv_msg_footer(nmbs);
1614 if (mei_type != 0x0E)
1617 if (read_device_id_code < 1 || read_device_id_code > 4)
1620 if (object_id > 6 && object_id < 0x80)
1632 return send_exception_msg(nmbs, err);
1637 put_res_header(nmbs, 0);
1639 put_1(nmbs, read_device_id_code);
1642 if (read_device_id_code == 4) {
1654 return send_exception_msg(nmbs, err);
1659 size_t str_len = strlen(str);
1661 put_1(nmbs, object_id);
1662 put_1(nmbs, str_len);
1663 put_n(nmbs, (uint8_t*) str, str_len);
1665 set_msg_header_size(nmbs, 6 + 2 + str_len);
1667 return send_msg(nmbs);
1670 uint8_t more_follows_idx = nmbs->
msg.
buf_idx;
1672 uint8_t next_object_id_idx = nmbs->
msg.
buf_idx;
1674 uint8_t number_of_objects_idx = nmbs->
msg.
buf_idx;
1677 int16_t res_size_left = 253 - 7;
1679 uint8_t last_id = 0;
1680 uint8_t msg_size = 6;
1681 uint8_t res_more_follows = 0;
1682 uint8_t res_next_object_id = 0;
1683 uint8_t res_number_of_objects = 0;
1685 switch (read_device_id_code) {
1687 if (object_id > 0x02)
1692 if (object_id < 0x03 || object_id > 0x07)
1697 if (object_id < 0x80)
1706 for (uint16_t
id = object_id;
id <= last_id;
id++) {
1717 return send_exception_msg(nmbs, err);
1722 int16_t str_len = (int16_t) strlen(str);
1724 res_size_left = (int16_t) (res_size_left - 2 - str_len);
1725 if (res_size_left < 0) {
1726 res_more_follows = 0xFF;
1727 res_next_object_id = id;
1731 put_1(nmbs, (uint8_t)
id);
1732 put_1(nmbs, str_len);
1733 put_n(nmbs, (uint8_t*) str, str_len);
1735 msg_size += (2 + str_len);
1737 res_number_of_objects++;
1740 set_1(nmbs, res_more_follows, more_follows_idx);
1741 set_1(nmbs, res_next_object_id, next_object_id_idx);
1742 set_1(nmbs, res_number_of_objects, number_of_objects_idx);
1744 set_msg_header_size(nmbs, msg_size);
1746 return send_msg(nmbs);
1762 switch (nmbs->
msg.
fc) {
1763#ifndef NMBS_SERVER_READ_COILS_DISABLED
1765 err = handle_read_coils(nmbs);
1769#ifndef NMBS_SERVER_READ_DISCRETE_INPUTS_DISABLED
1771 err = handle_read_discrete_inputs(nmbs);
1775#ifndef NMBS_SERVER_READ_HOLDING_REGISTERS_DISABLED
1777 err = handle_read_holding_registers(nmbs);
1781#ifndef NMBS_SERVER_READ_INPUT_REGISTERS_DISABLED
1783 err = handle_read_input_registers(nmbs);
1787#ifndef NMBS_SERVER_WRITE_SINGLE_COIL_DISABLED
1789 err = handle_write_single_coil(nmbs);
1793#ifndef NMBS_SERVER_WRITE_SINGLE_REGISTER_DISABLED
1795 err = handle_write_single_register(nmbs);
1799#ifndef NMBS_SERVER_WRITE_MULTIPLE_COILS_DISABLED
1801 err = handle_write_multiple_coils(nmbs);
1805#ifndef NMBS_SERVER_WRITE_MULTIPLE_REGISTERS_DISABLED
1807 err = handle_write_multiple_registers(nmbs);
1811#ifndef NMBS_SERVER_READ_FILE_RECORD_DISABLED
1813 err = handle_read_file_record(nmbs);
1817#ifndef NMBS_SERVER_WRITE_FILE_RECORD_DISABLED
1819 err = handle_write_file_record(nmbs);
1823#ifndef NMBS_SERVER_READ_WRITE_REGISTERS_DISABLED
1825 err = handle_read_write_registers(nmbs);
1829#ifndef NMBS_SERVER_READ_DEVICE_IDENTIFICATION_DISABLED
1831 err = handle_read_device_identification(nmbs);
1859 msg_state_reset(nmbs);
1861 bool first_byte_received =
false;
1862 nmbs_error err = recv_req_header(nmbs, &first_byte_received);
1872 printf(
"NMBS req <- ");
1875 printf(
"broadcast\t");
1877 printf(
"address_rtu %d\t", nmbs->
msg.
unit_id);
1881 err = handle_req_fc(nmbs);
1900#ifndef NMBS_CLIENT_DISABLED
1907 if (quantity < 1 || quantity > 2000)
1910 if ((uint32_t) address + (uint32_t) quantity > ((uint32_t) 0xFFFF) + 1)
1913 msg_state_req(nmbs, fc);
1914 put_req_header(nmbs, 4);
1916 put_2(nmbs, address);
1917 put_2(nmbs, quantity);
1925 return recv_read_discrete_res(nmbs, values);
1930 return read_discrete(nmbs, 1, address, quantity, coils_out);
1935 return read_discrete(nmbs, 2, address, quantity, inputs_out);
1938static nmbs_error read_registers(
nmbs_t* nmbs, uint8_t fc, uint16_t address, uint16_t quantity, uint16_t* registers) {
1939 if (quantity < 1 || quantity > 125)
1942 if ((uint32_t) address + (uint32_t) quantity > ((uint32_t) 0xFFFF) + 1)
1945 msg_state_req(nmbs, fc);
1946 put_req_header(nmbs, 4);
1948 put_2(nmbs, address);
1949 put_2(nmbs, quantity);
1957 return recv_read_registers_res(nmbs, quantity, registers);
1962 return read_registers(nmbs, 3, address, quantity, registers_out);
1967 return read_registers(nmbs, 4, address, quantity, registers_out);
1972 msg_state_req(nmbs, 5);
1973 put_req_header(nmbs, 4);
1975 put_2(nmbs, address);
1991 msg_state_req(nmbs, 6);
1992 put_req_header(nmbs, 4);
1994 put_2(nmbs, address);
2011 if (quantity < 1 || quantity > 0x07B0)
2014 if ((uint32_t) address + (uint32_t) quantity > ((uint32_t) 0xFFFF) + 1)
2017 uint8_t coils_bytes = (quantity + 7) / 8;
2019 msg_state_req(nmbs, 15);
2020 put_req_header(nmbs, 5 + coils_bytes);
2022 put_2(nmbs, address);
2023 put_2(nmbs, quantity);
2024 put_1(nmbs, coils_bytes);
2028 for (
int i = 0; i < coils_bytes; i++) {
2029 put_1(nmbs, coils[i]);
2045 if (quantity < 1 || quantity > 0x007B)
2048 if ((uint32_t) address + (uint32_t) quantity > ((uint32_t) 0xFFFF) + 1)
2051 uint8_t registers_bytes = quantity * 2;
2053 msg_state_req(nmbs, 16);
2054 put_req_header(nmbs, 5 + registers_bytes);
2056 put_2(nmbs, address);
2057 put_2(nmbs, quantity);
2058 put_1(nmbs, registers_bytes);
2059 NMBS_DEBUG_PRINT(
"a %d\tq %d\tb %d\t", address, quantity, registers_bytes);
2062 for (
int i = 0; i < quantity; i++) {
2063 put_2(nmbs, registers[i]);
2080 if (file_number == 0x0000)
2083 if (record_number > 0x270F)
2090 msg_state_req(nmbs, 20);
2091 put_req_header(nmbs, 8);
2095 put_2(nmbs, file_number);
2096 put_2(nmbs, record_number);
2098 NMBS_DEBUG_PRINT(
"a %d\tr %d\tl %d\t fread ", file_number, record_number, count);
2110 if (file_number == 0x0000)
2113 if (record_number > 0x270F)
2119 uint16_t data_size = count * 2;
2121 msg_state_req(nmbs, 21);
2122 put_req_header(nmbs, 8 + data_size);
2124 put_1(nmbs, 7 + data_size);
2126 put_2(nmbs, file_number);
2127 put_2(nmbs, record_number);
2129 put_regs(nmbs, registers, count);
2130 NMBS_DEBUG_PRINT(
"a %d\tr %d\tl %d\t fwrite ", file_number, record_number, count);
2144 uint16_t* registers_out, uint16_t write_address, uint16_t write_quantity,
2145 const uint16_t* registers) {
2146 if (read_quantity < 1 || read_quantity > 0x007D)
2149 if ((uint32_t) read_address + (uint32_t) read_quantity > ((uint32_t) 0xFFFF) + 1)
2152 if (write_quantity < 1 || write_quantity > 0x0079)
2155 if ((uint32_t) write_address + (uint32_t) write_quantity > ((uint32_t) 0xFFFF) + 1)
2158 uint8_t registers_bytes = write_quantity * 2;
2160 msg_state_req(nmbs, 23);
2161 put_req_header(nmbs, 9 + registers_bytes);
2163 put_2(nmbs, read_address);
2164 put_2(nmbs, read_quantity);
2165 put_2(nmbs, write_address);
2166 put_2(nmbs, write_quantity);
2167 put_1(nmbs, registers_bytes);
2170 NMBS_DEBUG_PRINT(
"write a %d\tq %d\tb %d\t", write_address, write_quantity, registers_bytes);
2173 for (
int i = 0; i < write_quantity; i++) {
2174 put_2(nmbs, registers[i]);
2183 return recv_read_registers_res(nmbs, read_quantity, registers_out);
2191 char* major_minor_revision, uint8_t buffers_length) {
2192 const uint8_t order[3] = {0, 1, 2};
2193 char* buffers[3] = {vendor_name, product_code, major_minor_revision};
2194 uint8_t total_received = 0;
2195 uint8_t next_object_id = 0x00;
2197 while (next_object_id != 0x7F) {
2198 msg_state_req(nmbs, 43);
2199 put_msg_header(nmbs, 3);
2202 put_1(nmbs, next_object_id);
2208 uint8_t objects_received = 0;
2214 total_received += objects_received;
2215 if (total_received > 3)
2218 if (objects_received == 0)
2227 char* user_application_name, uint8_t buffers_length) {
2228 const uint8_t order[7] = {0, 0, 0, 0, 1, 2, 3};
2229 char* buffers[4] = {vendor_url, product_name, model_name, user_application_name};
2230 uint8_t total_received = 0;
2231 uint8_t next_object_id = 0x03;
2233 while (next_object_id != 0x7F) {
2234 msg_state_req(nmbs, 43);
2235 put_req_header(nmbs, 3);
2238 put_1(nmbs, next_object_id);
2244 uint8_t objects_received = 0;
2250 total_received += objects_received;
2251 if (total_received > 4)
2254 if (objects_received == 0)
2263 uint8_t ids_length, uint8_t buffer_length,
2264 uint8_t* objects_count_out) {
2265 if (object_id_start < 0x80)
2268 uint8_t total_received = 0;
2269 uint8_t next_object_id = object_id_start;
2271 while (next_object_id != 0x7F) {
2272 msg_state_req(nmbs, 43);
2273 put_req_header(nmbs, 3);
2276 put_1(nmbs, next_object_id);
2282 uint8_t objects_received = 0;
2284 buffer_length, NULL, &ids[total_received], &next_object_id,
2289 total_received += objects_received;
2292 *objects_count_out = total_received;
2299 if (object_id > 0x06 && object_id < 0x80)
2302 msg_state_req(nmbs, 43);
2303 put_req_header(nmbs, 3);
2306 put_1(nmbs, object_id);
2312 char* buf[1] = {buffer};
2318 msg_state_req(nmbs, fc);
2319 put_msg_header(nmbs, data_len);
2322 for (uint16_t i = 0; i < data_len; i++) {
2323 put_1(nmbs, data[i]);
2327 return send_msg(nmbs);
2336 err = recv(nmbs, data_out_len);
2341 for (uint16_t i = 0; i < data_out_len; i++)
2342 data_out[i] = get_1(nmbs);
2345 for (uint16_t i = 0; i < data_out_len; i++)
2349 err = recv_msg_footer(nmbs);
2358#ifndef NMBS_STRERROR_DISABLED
2362 return "invalid request received";
2365 return "invalid unit ID received";
2368 return "invalid TCP MBAP received";
2371 return "invalid CRC received";
2374 return "transport error";
2380 return "invalid response received";
2383 return "invalid argument provided";
2389 return "modbus exception 1: illegal function";
2392 return "modbus exception 2: illegal data address";
2395 return "modbus exception 3: data value";
2398 return "modbus exception 4: server device failure";
2401 return "unknown error";
nmbs_error nmbs_read_input_registers(nmbs_t *nmbs, uint16_t address, uint16_t quantity, uint16_t *registers_out)
nmbs_error nmbs_write_multiple_registers(nmbs_t *nmbs, uint16_t address, uint16_t quantity, const uint16_t *registers)
nmbs_error nmbs_write_single_register(nmbs_t *nmbs, uint16_t address, uint16_t value)
nmbs_error nmbs_send_raw_pdu(nmbs_t *nmbs, uint8_t fc, const uint8_t *data, uint16_t data_len)
nmbs_error recv_read_device_identification_res(nmbs_t *nmbs, uint8_t buffers_count, char **buffers_out, uint8_t buffers_length, const uint8_t *order, uint8_t *ids_out, uint8_t *next_object_id_out, uint8_t *objects_count_out)
nmbs_error nmbs_client_create(nmbs_t *nmbs, const nmbs_platform_conf *platform_conf)
nmbs_error recv_write_file_record_res(nmbs_t *nmbs, uint16_t file_number, uint16_t record_number, const uint16_t *registers, uint16_t count)
nmbs_error nmbs_read_device_identification_regular(nmbs_t *nmbs, char *vendor_url, char *product_name, char *model_name, char *user_application_name, uint8_t buffers_length)
nmbs_error recv_read_file_record_res(nmbs_t *nmbs, uint16_t *registers, uint16_t count)
void nmbs_set_byte_timeout(nmbs_t *nmbs, int32_t timeout_ms)
nmbs_error recv_write_multiple_registers_res(nmbs_t *nmbs, uint16_t address, uint16_t quantity)
nmbs_error nmbs_read_holding_registers(nmbs_t *nmbs, uint16_t address, uint16_t quantity, uint16_t *registers_out)
void nmbs_set_destination_rtu_address(nmbs_t *nmbs, uint8_t address)
nmbs_error nmbs_receive_raw_pdu_response(nmbs_t *nmbs, uint8_t *data_out, uint8_t data_out_len)
nmbs_error nmbs_server_poll(nmbs_t *nmbs)
const char * nmbs_strerror(nmbs_error error)
nmbs_error nmbs_read_device_identification_basic(nmbs_t *nmbs, char *vendor_name, char *product_code, char *major_minor_revision, uint8_t buffers_length)
nmbs_error recv_write_multiple_coils_res(nmbs_t *nmbs, uint16_t address, uint16_t quantity)
nmbs_error nmbs_write_file_record(nmbs_t *nmbs, uint16_t file_number, uint16_t record_number, const uint16_t *registers, uint16_t count)
nmbs_error nmbs_write_single_coil(nmbs_t *nmbs, uint16_t address, uint16_t value)
nmbs_error nmbs_write_multiple_coils(nmbs_t *nmbs, uint16_t address, uint16_t quantity, const nmbs_bitfield coils)
void nmbs_set_callbacks_arg(nmbs_t *nmbs, void *arg)
nmbs_error nmbs_read_device_identification_extended(nmbs_t *nmbs, uint8_t object_id_start, uint8_t *ids, char **buffers, uint8_t ids_length, uint8_t buffer_length, uint8_t *objects_count_out)
nmbs_error nmbs_server_create(nmbs_t *nmbs, uint8_t address_rtu, const nmbs_platform_conf *platform_conf, const nmbs_callbacks *callbacks)
nmbs_error nmbs_create(nmbs_t *nmbs, const nmbs_platform_conf *platform_conf)
nmbs_error recv_write_single_register_res(nmbs_t *nmbs, uint16_t address, uint16_t value_req)
nmbs_error nmbs_read_coils(nmbs_t *nmbs, uint16_t address, uint16_t quantity, nmbs_bitfield coils_out)
nmbs_error nmbs_read_file_record(nmbs_t *nmbs, uint16_t file_number, uint16_t record_number, uint16_t *registers, uint16_t count)
void nmbs_set_read_timeout(nmbs_t *nmbs, int32_t timeout_ms)
void nmbs_set_platform_arg(nmbs_t *nmbs, void *arg)
nmbs_error nmbs_read_write_registers(nmbs_t *nmbs, uint16_t read_address, uint16_t read_quantity, uint16_t *registers_out, uint16_t write_address, uint16_t write_quantity, const uint16_t *registers)
nmbs_error recv_write_single_coil_res(nmbs_t *nmbs, uint16_t address, uint16_t value_req)
uint16_t nmbs_crc_calc(const uint8_t *data, uint32_t length)
#define NMBS_DEBUG_PRINT(...)
nmbs_error nmbs_read_discrete_inputs(nmbs_t *nmbs, uint16_t address, uint16_t quantity, nmbs_bitfield inputs_out)
nmbs_error nmbs_read_device_identification(nmbs_t *nmbs, uint8_t object_id, char *buffer, uint8_t buffer_length)
@ NMBS_ERROR_INVALID_UNIT_ID
@ NMBS_ERROR_INVALID_ARGUMENT
@ NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS
@ NMBS_ERROR_INVALID_TCP_MBAP
@ NMBS_ERROR_INVALID_REQUEST
@ NMBS_ERROR_INVALID_RESPONSE
@ NMBS_EXCEPTION_ILLEGAL_DATA_VALUE
@ NMBS_EXCEPTION_ILLEGAL_FUNCTION
@ NMBS_EXCEPTION_SERVER_DEVICE_FAILURE
uint8_t nmbs_bitfield[250]
#define nmbs_bitfield_reset(bf)
#define nmbs_bitfield_read(bf, b)
#define NMBS_DEVICE_IDENTIFICATION_STRING_LENGTH
uint8_t nmbs_bitfield_256[32]
#define nmbs_error_is_exception(e)
nmbs_error(* write_single_coil)(uint16_t address, bool value, uint8_t unit_id, void *arg)
nmbs_error(* write_multiple_registers)(uint16_t address, uint16_t quantity, const uint16_t *registers, uint8_t unit_id, void *arg)
nmbs_error(* write_file_record)(uint16_t file_number, uint16_t record_number, const uint16_t *registers, uint16_t count, uint8_t unit_id, void *arg)
nmbs_error(* read_input_registers)(uint16_t address, uint16_t quantity, uint16_t *registers_out, uint8_t unit_id, void *arg)
nmbs_error(* read_file_record)(uint16_t file_number, uint16_t record_number, uint16_t *registers, uint16_t count, uint8_t unit_id, void *arg)
nmbs_error(* read_coils)(uint16_t address, uint16_t quantity, nmbs_bitfield coils_out, uint8_t unit_id, void *arg)
nmbs_error(* read_discrete_inputs)(uint16_t address, uint16_t quantity, nmbs_bitfield inputs_out, uint8_t unit_id, void *arg)
nmbs_error(* write_single_register)(uint16_t address, uint16_t value, uint8_t unit_id, void *arg)
nmbs_error(* read_holding_registers)(uint16_t address, uint16_t quantity, uint16_t *registers_out, uint8_t unit_id, void *arg)
nmbs_error(* read_device_identification_map)(nmbs_bitfield_256 map)
nmbs_error(* read_device_identification)(uint8_t object_id, char buffer[NMBS_DEVICE_IDENTIFICATION_STRING_LENGTH])
nmbs_error(* write_multiple_coils)(uint16_t address, uint16_t quantity, const nmbs_bitfield coils, uint8_t unit_id, void *arg)
nmbs_platform_conf platform