From 1372e52aa773c225693d6ef9ef267be2b1c7122e Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Wed, 8 Nov 2023 15:54:18 -0600 Subject: [PATCH] Feature/mstp extended frames (#529) * added MSTP extended frames to bacnet/datalink/mstp.c module. Thank you, Simon! * auto-size some FIFO buffers for MSTP * add COBS library to MSTP builds --------- Co-authored-by: Steve Karg --- CHANGELOG.md | 29 +++++++++-- CMakeLists.txt | 1 + apps/fuzz-afl/Makefile | 1 + apps/fuzz-libfuzzer/Makefile | 1 + apps/lib/Makefile | 1 + apps/mstpcap/Makefile | 1 + apps/router-mstp/Makefile | 1 + apps/router/Makefile | 1 + ports/bdk-atxx4-mstp/rs485.c | 2 +- ports/pic18f6720/rs485.c | 4 +- ports/pic18f97j60/rs485.c | 4 +- ports/stm32f10x/rs485.c | 3 +- ports/stm32f4xx/Makefile | 2 +- ports/stm32f4xx/bacnet.ewp | 2 +- ports/stm32f4xx/rs485.c | 9 ++-- .../BACnet_Stack_Library.vcxproj | 1 + .../bacnet-stack/bacnet-stack.vcxproj | 1 + ports/xplained/rs485.c | 3 +- src/bacnet/config.h | 14 ++++- src/bacnet/datalink/dlenv.c | 2 + src/bacnet/datalink/mstp.c | 51 ++++++++++++++----- src/bacnet/datalink/mstptext.c | 7 ++- 22 files changed, 109 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b7c844d..eb8a71aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,25 +18,44 @@ The git repositories are hosted at the following sites: ### Added +- Added MSTP extended frames to src/datalink/mstp.c module used by mstpcap (#529) +- Added menu to release script (#506) + ### Changed +- Change SubscribeCOV Cancellations to always reply with Result+ (#526) +- Allow processing of Who-Has when DCC initiation is disabled + ### Fixed +- Fix BACnet/IP builds for BBMD clients without BBMD tables. (#523) +- Fix decoding empty array of complex type in RPM +- Fix device object ReinitializeDevice service handling examples of + no-password in the device. (#518) +- Fix DeviceCommunicationControl service handling example of + no-password in the device. (#518) +- Fix incorrect apdu_len calculation when encoding Recipient_List + which had resulted in malformed APDU. (#517) +- Fix reinitializing a bacnet stack on windows by checking + for valid socket before cleaning up WSA (#514) +- Fix a warning that 'device_id' is not used (#510) +- Added new linear.c to Microsoft Visual Studio project (#507) + ## [1.3.1] - 2023-09-29 ### Added -Added example Channel object WriteProperty callback into example Device objects. (#504) -Added Microsoft Visual Studio 2022 Community Edition solution to ports/win32 (#502) -Added details in apps/blinkt example about starting app with systemd (#505) +- Added example Channel object WriteProperty callback into example Device objects. (#504) +- Added Microsoft Visual Studio 2022 Community Edition solution to ports/win32 (#502) +- Added details in apps/blinkt example about starting app with systemd (#505) ### Fixed -Refactored WriteProperty of object-name property rules into example device object (#504) +- Refactored WriteProperty of object-name property rules into example device object (#504) ### Changed -Changed WriteProperty string property checker to ignore length check with zero option.(#504) +- Changed WriteProperty string property checker to ignore length check with zero option.(#504) ## [1.3.0] - 2023-09-28 diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b9307dc..6772d028 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -392,6 +392,7 @@ add_library(${PROJECT_NAME} $<$:src/bacnet/datalink/bvlc.c> $<$:src/bacnet/datalink/crc.h> $<$:src/bacnet/datalink/crc.c> + $<$:src/bacnet/datalink/cobs.h> $<$:src/bacnet/datalink/cobs.c> src/bacnet/datalink/datalink.c src/bacnet/datalink/datalink.h diff --git a/apps/fuzz-afl/Makefile b/apps/fuzz-afl/Makefile index 0482f2b8..3c1fcc07 100644 --- a/apps/fuzz-afl/Makefile +++ b/apps/fuzz-afl/Makefile @@ -19,6 +19,7 @@ SRC = main.c \ PORT_MSTP_SRC = \ $(BACNET_PORT_DIR)/rs485.c \ $(BACNET_PORT_DIR)/dlmstp.c \ + $(BACNET_SRC_DIR)/bacnet/datalink/cobs.c \ $(BACNET_SRC_DIR)/bacnet/datalink/mstp.c \ $(BACNET_SRC_DIR)/bacnet/datalink/mstptext.c \ $(BACNET_SRC_DIR)/bacnet/datalink/crc.c diff --git a/apps/fuzz-libfuzzer/Makefile b/apps/fuzz-libfuzzer/Makefile index dd189380..9de81e29 100644 --- a/apps/fuzz-libfuzzer/Makefile +++ b/apps/fuzz-libfuzzer/Makefile @@ -21,6 +21,7 @@ SRC = main.c \ PORT_MSTP_SRC = \ $(BACNET_PORT_DIR)/rs485.c \ $(BACNET_PORT_DIR)/dlmstp.c \ + $(BACNET_SRC_DIR)/bacnet/datalink/cobs.c \ $(BACNET_SRC_DIR)/bacnet/datalink/mstp.c \ $(BACNET_SRC_DIR)/bacnet/datalink/mstptext.c \ $(BACNET_SRC_DIR)/bacnet/datalink/crc.c diff --git a/apps/lib/Makefile b/apps/lib/Makefile index eb04103f..abdf1a7f 100644 --- a/apps/lib/Makefile +++ b/apps/lib/Makefile @@ -29,6 +29,7 @@ PORT_ARCNET_SRC = \ PORT_MSTP_SRC = \ $(BACNET_PORT_DIR)/rs485.c \ $(BACNET_PORT_DIR)/dlmstp.c \ + $(BACNET_SRC_DIR)/bacnet/datalink/cobs.c \ $(BACNET_SRC_DIR)/bacnet/datalink/mstp.c \ $(BACNET_SRC_DIR)/bacnet/datalink/mstptext.c \ $(BACNET_SRC_DIR)/bacnet/datalink/crc.c diff --git a/apps/mstpcap/Makefile b/apps/mstpcap/Makefile index e56ed5cd..88482307 100644 --- a/apps/mstpcap/Makefile +++ b/apps/mstpcap/Makefile @@ -23,6 +23,7 @@ SRCS = main.c \ ${BACNET_SRC_DIR}/bacnet/basic/sys/filename.c \ ${BACNET_SRC_DIR}/bacnet/basic/sys/mstimer.c \ ${BACNET_SRC_DIR}/bacnet/basic/sys/ringbuf.c \ + ${BACNET_SRC_DIR}/bacnet/datalink/cobs.c \ ${BACNET_SRC_DIR}/bacnet/datalink/mstp.c \ ${BACNET_SRC_DIR}/bacnet/datalink/mstptext.c \ ${BACNET_SRC_DIR}/bacnet/datalink/crc.c diff --git a/apps/router-mstp/Makefile b/apps/router-mstp/Makefile index ec3086a2..848827b8 100644 --- a/apps/router-mstp/Makefile +++ b/apps/router-mstp/Makefile @@ -19,6 +19,7 @@ SRC = main.c \ PORT_MSTP_SRC = \ $(BACNET_PORT_DIR)/rs485.c \ $(BACNET_PORT_DIR)/dlmstp.c \ + $(BACNET_SRC_DIR)/bacnet/datalink/cobs.c \ $(BACNET_SRC_DIR)/bacnet/datalink/mstp.c \ $(BACNET_SRC_DIR)/bacnet/datalink/mstptext.c \ $(BACNET_SRC_DIR)/bacnet/datalink/crc.c diff --git a/apps/router/Makefile b/apps/router/Makefile index 8d4428b8..c8999cff 100644 --- a/apps/router/Makefile +++ b/apps/router/Makefile @@ -29,6 +29,7 @@ SRCS = main.c \ ${BACNET_SOURCE_DIR}/basic/bbmd/h_bbmd.c \ ${BACNET_SOURCE_DIR}/datalink/bvlc.c \ ${BACNET_SOURCE_DIR}/basic/sys/fifo.c \ + ${BACNET_SOURCE_DIR}/datalink/cobs.c \ ${BACNET_SOURCE_DIR}/datalink/mstp.c \ ${BACNET_SOURCE_DIR}/datalink/mstptext.c \ ${BACNET_SOURCE_DIR}/basic/sys/debug.c \ diff --git a/ports/bdk-atxx4-mstp/rs485.c b/ports/bdk-atxx4-mstp/rs485.c index e5299ea7..5d38cadc 100644 --- a/ports/bdk-atxx4-mstp/rs485.c +++ b/ports/bdk-atxx4-mstp/rs485.c @@ -48,7 +48,7 @@ static uint32_t Baud_Rate = 9600; /* turnaround_time_milliseconds = (Tturnaround*1000UL)/Baud_Rate; */ /* buffer for storing received bytes - size must be power of two */ -static uint8_t Receive_Buffer_Data[128]; +static uint8_t Receive_Buffer_Data[256]; static FIFO_BUFFER Receive_Buffer; static struct mstimer Silence_Timer; diff --git a/ports/pic18f6720/rs485.c b/ports/pic18f6720/rs485.c index ca9678a0..0ee4cf24 100644 --- a/ports/pic18f6720/rs485.c +++ b/ports/pic18f6720/rs485.c @@ -46,9 +46,9 @@ FIFO_BUFFER FIFO_Rx; FIFO_BUFFER FIFO_Tx; #pragma udata MSTPPortData /* the buffer for receiving data (size must be a power of 2) */ -volatile uint8_t RS485_Rx_Buffer[128]; +volatile uint8_t RS485_Rx_Buffer[NEXT_POWER_OF_2(DLMSTP_MPDU_MAX)]; /* the buffer for sending data (size must be a power of 2) */ -volatile uint8_t RS485_Tx_Buffer[128]; +volatile uint8_t RS485_Tx_Buffer[NEXT_POWER_OF_2(DLMSTP_MPDU_MAX)]; #pragma udata /**************************************************************************** diff --git a/ports/pic18f97j60/rs485.c b/ports/pic18f97j60/rs485.c index ca9678a0..0ee4cf24 100644 --- a/ports/pic18f97j60/rs485.c +++ b/ports/pic18f97j60/rs485.c @@ -46,9 +46,9 @@ FIFO_BUFFER FIFO_Rx; FIFO_BUFFER FIFO_Tx; #pragma udata MSTPPortData /* the buffer for receiving data (size must be a power of 2) */ -volatile uint8_t RS485_Rx_Buffer[128]; +volatile uint8_t RS485_Rx_Buffer[NEXT_POWER_OF_2(DLMSTP_MPDU_MAX)]; /* the buffer for sending data (size must be a power of 2) */ -volatile uint8_t RS485_Tx_Buffer[128]; +volatile uint8_t RS485_Tx_Buffer[NEXT_POWER_OF_2(DLMSTP_MPDU_MAX)]; #pragma udata /**************************************************************************** diff --git a/ports/stm32f10x/rs485.c b/ports/stm32f10x/rs485.c index 99064921..2c6f1f2e 100644 --- a/ports/stm32f10x/rs485.c +++ b/ports/stm32f10x/rs485.c @@ -30,12 +30,13 @@ #include "hardware.h" #include "bacnet/basic/sys/mstimer.h" #include "bacnet/bits.h" +#include "bacnet/datalink/dlmstp.h" #include "bacnet/basic/sys/fifo.h" #include "led.h" #include "rs485.h" /* buffer for storing received bytes - size must be power of two */ -static uint8_t Receive_Buffer_Data[512]; +static uint8_t Receive_Buffer_Data[NEXT_POWER_OF_2(DLMSTP_MPDU_MAX)]; static FIFO_BUFFER Receive_Buffer; /* amount of silence on the wire */ static struct mstimer Silence_Timer; diff --git a/ports/stm32f4xx/Makefile b/ports/stm32f4xx/Makefile index c5b91112..f8214644 100644 --- a/ports/stm32f4xx/Makefile +++ b/ports/stm32f4xx/Makefile @@ -137,7 +137,7 @@ OPTIMIZE_FLAGS += -DNDEBUG BACNET_FLAGS = -DBACDL_MSTP=1 BACNET_FLAGS += -DBACAPP_ALL -BACNET_FLAGS += -DMAX_APDU=480 +BACNET_FLAGS += -DMAX_APDU=1476 BACNET_FLAGS += -DBIG_ENDIAN=0 BACNET_FLAGS += -DMAX_TSM_TRANSACTIONS=0 BACNET_FLAGS += -DMAX_CHARACTER_STRING_BYTES=64 diff --git a/ports/stm32f4xx/bacnet.ewp b/ports/stm32f4xx/bacnet.ewp index 6c3d169d..043296fb 100644 --- a/ports/stm32f4xx/bacnet.ewp +++ b/ports/stm32f4xx/bacnet.ewp @@ -224,7 +224,7 @@ USE_STDPERIPH_DRIVER STM32F4XX BACDL_MSTP - MAX_APDU=480 + MAX_APDU=1476 BIG_ENDIAN=0 MAX_TSM_TRANSACTIONS=1 diff --git a/ports/stm32f4xx/rs485.c b/ports/stm32f4xx/rs485.c index 6c8fe62d..1a7b7749 100644 --- a/ports/stm32f4xx/rs485.c +++ b/ports/stm32f4xx/rs485.c @@ -33,17 +33,18 @@ #include "bacnet/basic/sys/mstimer.h" #include "bacnet/bits.h" #include "bacnet/basic/sys/fifo.h" +#include "bacnet/datalink/dlmstp.h" #include "bacnet/datalink/mstpdef.h" #include "rs485.h" /* buffer for storing received bytes - size must be power of two */ -/* BACnet DLMSTP_MPDU_MAX for MS/TP is 501 bytes */ -static uint8_t Receive_Queue_Data[512]; +/* BACnet DLMSTP_MPDU_MAX for MS/TP is 1501 bytes */ +static uint8_t Receive_Queue_Data[NEXT_POWER_OF_2(DLMSTP_MPDU_MAX)]; static FIFO_BUFFER Receive_Queue; /* buffer for storing bytes to transmit */ -/* BACnet DLMSTP_MPDU_MAX for MS/TP is 501 bytes */ -static uint8_t Transmit_Queue_Data[512]; +/* BACnet DLMSTP_MPDU_MAX for MS/TP is 1501 bytes */ +static uint8_t Transmit_Queue_Data[NEXT_POWER_OF_2(DLMSTP_MPDU_MAX)]; static FIFO_BUFFER Transmit_Queue; /* baud rate of the UART interface */ diff --git a/ports/win32/Microsoft Visual Studio 2019/BACnet_Stack_Library/BACnet_Stack_Library.vcxproj b/ports/win32/Microsoft Visual Studio 2019/BACnet_Stack_Library/BACnet_Stack_Library.vcxproj index ab2ae697..0cce8639 100644 --- a/ports/win32/Microsoft Visual Studio 2019/BACnet_Stack_Library/BACnet_Stack_Library.vcxproj +++ b/ports/win32/Microsoft Visual Studio 2019/BACnet_Stack_Library/BACnet_Stack_Library.vcxproj @@ -201,6 +201,7 @@ + diff --git a/ports/win32/Microsoft Visual Studio/bacnet-stack/bacnet-stack.vcxproj b/ports/win32/Microsoft Visual Studio/bacnet-stack/bacnet-stack.vcxproj index 8be7b02c..6afc33d9 100644 --- a/ports/win32/Microsoft Visual Studio/bacnet-stack/bacnet-stack.vcxproj +++ b/ports/win32/Microsoft Visual Studio/bacnet-stack/bacnet-stack.vcxproj @@ -161,6 +161,7 @@ + diff --git a/ports/xplained/rs485.c b/ports/xplained/rs485.c index 05e0caf2..4a95c1e4 100644 --- a/ports/xplained/rs485.c +++ b/ports/xplained/rs485.c @@ -35,8 +35,9 @@ #include "sysclk.h" #include "bacnet/basic/sys/fifo.h" #include "bacnet/basic/sys/mstimer.h" -#include "led.h" +#include "bacnet/datalink/dlmstp.h" #include "bacnet/datalink/mstpdef.h" +#include "led.h" /* me! */ #include "rs485.h" diff --git a/src/bacnet/config.h b/src/bacnet/config.h index 04700c69..1ec2c341 100644 --- a/src/bacnet/config.h +++ b/src/bacnet/config.h @@ -80,7 +80,7 @@ /* Typical sizes are 50, 128, 206, 480, 1024, and 1476 octets */ /* This is used in constructing messages and to tell others our limits */ /* 50 is the minimum; adjust to your memory and physical layer constraints */ -/* Lon=206, MS/TP=480, ARCNET=480, Ethernet=1476, BACnet/IP=1476 */ +/* Lon=206, MS/TP=480 or 1476, ARCNET=480, Ethernet=1476, BACnet/IP=1476 */ #if !defined(MAX_APDU) /* #define MAX_APDU 50 */ /* #define MAX_APDU 1476 */ @@ -96,6 +96,18 @@ #else #define MAX_APDU 1476 #endif +#elif defined (BACDL_ARCNET) +#if defined(BACNET_SECURITY) +#define MAX_APDU 412 +#else +#define MAX_APDU 480 +#endif +#elif defined (BACDL_MSTP) +#if defined(BACNET_SECURITY) +#define MAX_APDU 412 +#else +#define MAX_APDU 1476 +#endif #else #if defined(BACNET_SECURITY) #define MAX_APDU 412 diff --git a/src/bacnet/datalink/dlenv.c b/src/bacnet/datalink/dlenv.c index bbe5e38d..bee7ba32 100644 --- a/src/bacnet/datalink/dlenv.c +++ b/src/bacnet/datalink/dlenv.c @@ -483,6 +483,8 @@ void dlenv_maintenance_timer(uint16_t elapsed_seconds) BBMD_Timer_Seconds = (uint16_t)BBMD_TTL_Seconds; } } +#else + (void)elapsed_seconds; #endif } diff --git a/src/bacnet/datalink/mstp.c b/src/bacnet/datalink/mstp.c index 506fad87..678e942d 100644 --- a/src/bacnet/datalink/mstp.c +++ b/src/bacnet/datalink/mstp.c @@ -56,6 +56,7 @@ #include "rs485.h" #include "bacnet/datalink/mstptext.h" #include "bacnet/npdu.h" +#include "bacnet/datalink/cobs.h" #ifndef DEBUG_ENABLED #define DEBUG_ENABLED 0 @@ -532,30 +533,56 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port) mstp_port->DataCRC = CRC_Calc_Data( mstp_port->DataRegister, mstp_port->DataCRC); mstp_port->DataCRCActualMSB = mstp_port->DataRegister; + mstp_port->InputBuffer[mstp_port->Index] = + mstp_port->DataRegister; mstp_port->Index++; /* SKIP_DATA or DATA - no change in state */ } else if (mstp_port->Index == (mstp_port->DataLength + 1)) { /* CRC2 */ + mstp_port->InputBuffer[mstp_port->Index] = + mstp_port->DataRegister; mstp_port->DataCRC = CRC_Calc_Data( mstp_port->DataRegister, mstp_port->DataCRC); mstp_port->DataCRCActualLSB = mstp_port->DataRegister; printf_receive_data("%s", mstptext_frame_type((unsigned)mstp_port->FrameType)); - /* STATE DATA CRC - no need for new state */ - /* indicate the complete reception of a valid frame */ - if (mstp_port->DataCRC == 0xF0B8) { - if (mstp_port->receive_state == - MSTP_RECEIVE_STATE_DATA) { - /* ForUs */ - mstp_port->ReceivedValidFrame = true; + if ((mstp_port->FrameType == + FRAME_TYPE_BACNET_EXTENDED_DATA_EXPECTING_REPLY) || + (mstp_port->FrameType == + FRAME_TYPE_BACNET_EXTENDED_DATA_NOT_EXPECTING_REPLY)) { + if (cobs_frame_decode( + &mstp_port->InputBuffer[mstp_port->Index + 1], + mstp_port->InputBufferSize, + mstp_port->InputBuffer, mstp_port->Index + 1)) { + if (mstp_port->receive_state == + MSTP_RECEIVE_STATE_DATA) { + /* ForUs */ + mstp_port->ReceivedValidFrame = true; + } else { + /* NotForUs */ + mstp_port->ReceivedValidFrameNotForUs = true; + } } else { - /* NotForUs */ - mstp_port->ReceivedValidFrameNotForUs = true; + mstp_port->ReceivedInvalidFrame = true; } } else { - mstp_port->ReceivedInvalidFrame = true; - printf_receive_error("MSTP: Rx Data: BadCRC [%02X]\n", - mstp_port->DataRegister); + /* STATE DATA CRC - no need for new state */ + /* indicate the complete reception of a valid frame */ + if (mstp_port->DataCRC == 0xF0B8) { + if (mstp_port->receive_state == + MSTP_RECEIVE_STATE_DATA) { + /* ForUs */ + mstp_port->ReceivedValidFrame = true; + } else { + /* NotForUs */ + mstp_port->ReceivedValidFrameNotForUs = true; + } + } else { + mstp_port->ReceivedInvalidFrame = true; + printf_receive_error( + "MSTP: Rx Data: BadCRC [%02X]\n", + mstp_port->DataRegister); + } } mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; } else { diff --git a/src/bacnet/datalink/mstptext.c b/src/bacnet/datalink/mstptext.c index e10e07b2..71330a85 100644 --- a/src/bacnet/datalink/mstptext.c +++ b/src/bacnet/datalink/mstptext.c @@ -75,7 +75,12 @@ static INDTEXT_DATA mstp_frame_type_text[] = { { FRAME_TYPE_TOKEN, "TOKEN" }, { FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY, "BACNET_DATA_EXPECTING_REPLY" }, { FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY, "BACNET_DATA_NOT_EXPECTING_REPLY" }, - { FRAME_TYPE_REPLY_POSTPONED, "REPLY_POSTPONED" }, { 0, NULL } }; + { FRAME_TYPE_REPLY_POSTPONED, "REPLY_POSTPONED" }, + { FRAME_TYPE_BACNET_EXTENDED_DATA_EXPECTING_REPLY, + "BACNET_EXTENDED_DATA_EXPECTING_REPLY" }, + { FRAME_TYPE_BACNET_EXTENDED_DATA_NOT_EXPECTING_REPLY, + "BACNET_EXTENDED_DATA_NOT_EXPECTING_REPLY" }, + { FRAME_TYPE_IPV6_ENCAPSULATION, "IPV6_ENCAPSULATION" }, { 0, NULL } }; const char *mstptext_frame_type(unsigned index) {