From 0001f85f297c26f6158c2c0ba777a8f21f4cbc2b Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Fri, 8 Sep 2023 17:41:56 -0500 Subject: [PATCH] Bugfix/network port object link speeds (#488) * fix ports/xplained build under Linux * fix network port object link-speeds property --------- Co-authored-by: Steve Karg --- .github/workflows/gcc.yml | 1 + CHANGELOG.md | 4 + Makefile | 11 ++- ports/at91sam7s/Makefile | 4 + ports/at91sam7s/netport.c | 74 +++++++++++++++--- ports/bdk-atxx4-mstp/Makefile | 4 + ports/bdk-atxx4-mstp/netport.c | 73 +++++++++++++++--- ports/stm32f10x/Makefile | 4 + ports/stm32f10x/netport.c | 76 ++++++++++++++++--- ports/stm32f4xx/Makefile | 4 + ports/stm32f4xx/netport.c | 74 +++++++++++++++--- .../ASF/xmega/drivers/cpu/{ccp.s => ccp.S} | 0 .../drivers/nvm/{nvm_asm.s => nvm_asm.S} | 0 .../xplained/ASF/xmega/drivers/usart/usart.c | 5 +- ports/xplained/Makefile | 53 ++++++++++--- ports/xplained/device.c | 2 +- ports/xplained/mstimer-init.c | 10 +-- ports/xplained/netport.c | 74 +++++++++++++++--- src/bacnet/basic/object/netport.c | 3 +- src/bacnet/config.h | 1 + 20 files changed, 404 insertions(+), 73 deletions(-) rename ports/xplained/ASF/xmega/drivers/cpu/{ccp.s => ccp.S} (100%) rename ports/xplained/ASF/xmega/drivers/nvm/{nvm_asm.s => nvm_asm.S} (100%) diff --git a/.github/workflows/gcc.yml b/.github/workflows/gcc.yml index ff8b1823..848e375d 100644 --- a/.github/workflows/gcc.yml +++ b/.github/workflows/gcc.yml @@ -179,6 +179,7 @@ jobs: avr-gcc --version make atmega168 make bdk-atxx4-mstp + make xplained ports-lwip: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dd5d022..83c746d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,10 @@ improved unit test code coverage. (#481) ### Fixed +- Fixed missing Link_Speeds property in network port objects when +Link_Speed property is writable. +- Fixed Microchip xmega xplained example project to build under GCC in pipeline. + ## [1.1.2] - 2023-08-18 ### Security diff --git a/Makefile b/Makefile index d2136bd9..c67a4aaf 100644 --- a/Makefile +++ b/Makefile @@ -175,7 +175,8 @@ ports: atmega168 bdk-atxx4-mstp at91sam7s stm32f10x stm32f4xx @echo "Built the ARM7 and AVR ports" .PHONY: ports-clean -ports-clean: atmega168-clean bdk-atxx4-mstp-clean at91sam7s-clean stm32f10x-clean stm32f4xx-clean +ports-clean: atmega168-clean bdk-atxx4-mstp-clean at91sam7s-clean \ + stm32f10x-clean stm32f4xx-clean xplained-clean .PHONY: atmega168 atmega168: ports/atmega168/Makefile @@ -217,6 +218,14 @@ stm32f4xx: ports/stm32f4xx/Makefile stm32f4xx-clean: ports/stm32f4xx/Makefile $(MAKE) -s -C ports/stm32f4xx clean +.PHONY: xplained +xplained: ports/xplained/Makefile + $(MAKE) -s -C ports/xplained clean all + +.PHONY: xplained-clean +xplained-clean: ports/xplained/Makefile + $(MAKE) -s -C ports/xplained clean + .PHONY: mstpsnap mstpsnap: ports/linux/mstpsnap.mak $(MAKE) -s -C ports/linux -f mstpsnap.mak clean all diff --git a/ports/at91sam7s/Makefile b/ports/at91sam7s/Makefile index c5966062..28ca1a2e 100644 --- a/ports/at91sam7s/Makefile +++ b/ports/at91sam7s/Makefile @@ -23,6 +23,10 @@ BACNET_FLAGS += -DPRINT_ENABLED=0 BACNET_FLAGS += -DMAX_APDU=480 BACNET_FLAGS += -DCRC_USE_TABLE #BACNET_FLAGS += -DDLMSTP_TEST +ifeq (${LEGACY},true) +# disable deprecated function warnings for legacy builds +BACNET_FLAGS += -DBACNET_STACK_DEPRECATED_DISABLE +endif BACNET_SRC = ../../src BACNET_CORE = $(BACNET_SRC)/bacnet diff --git a/ports/at91sam7s/netport.c b/ports/at91sam7s/netport.c index 3a2899a6..f0d48ddb 100644 --- a/ports/at91sam7s/netport.c +++ b/ports/at91sam7s/netport.c @@ -47,7 +47,6 @@ /* MS/TP specific */ #include "bacnet/datalink/dlmstp.h" #include "rs485.h" -//#include "nvdata.h" /* me */ #include "bacnet/basic/object/netport.h" @@ -68,6 +67,10 @@ struct object_data Object_List[BACNET_NETWORK_PORTS_MAX]; #define BACNET_NETWORK_PORT_INSTANCE 1 #endif +/* BACnetARRAY of REAL, is an array of the link speeds + supported by this network port */ +static uint32_t Link_Speeds[] = {9600, 19200, 38400, 57600, 76800, 115200 }; + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_STATUS_FLAGS, PROP_RELIABILITY, @@ -76,7 +79,8 @@ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_APDU_LENGTH, PROP_LINK_SPEED, -1 }; static const int Network_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, - PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, -1 }; + PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_LINK_SPEEDS, + -1 }; static const int Network_Port_Properties_Proprietary[] = { -1 }; @@ -348,6 +352,41 @@ float Network_Port_Link_Speed(uint32_t object_instance) return Object_List[0].Link_Speed; } +/** + * @brief Get the number of Link speeds supported by this object + * @param object_instance [in] BACnet network port object instance number + * @return number of link-speed values supported by this object + */ +static unsigned Network_Port_Link_Speeds_Count(uint32_t object_instance) +{ + return ARRAY_SIZE(Link_Speeds); +} + +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +static int Network_Port_Link_Speeds_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + float link_speed; + + (void)object_instance; + if (array_index < ARRAY_SIZE(Link_Speeds)) { + link_speed = Link_Speeds[array_index]; + apdu_len = encode_application_real(apdu, link_speed); + } + + return apdu_len; +} + /** * @brief Set the device link speed (baud rate) * @param object_instance The object instance number of the object @@ -358,18 +397,16 @@ bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value) { bool status = false; uint32_t baud = (uint32_t)value; + unsigned i; - switch (baud) { - case 9600: - case 19200: - case 38400: - case 57600: - case 76800: - case 115200: + (void)object_instance; + for (i = 0; i < ARRAY_SIZE(Link_Speeds); i++) { + if (Link_Speeds[i] == baud) { Object_List[0].Link_Speed = value; Object_List[0].Changes_Pending = true; status = true; break; + } } return status; @@ -497,17 +534,19 @@ bool Network_Port_MSTP_Max_Info_Frames_Set( */ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { - int apdu_len = 0; + int apdu_len = 0, apdu_max; BACNET_BIT_STRING bit_string; BACNET_OCTET_STRING octet_string; BACNET_CHARACTER_STRING char_string; uint8_t *apdu = NULL; + unsigned count; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -577,6 +616,20 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_real( &apdu[0], Network_Port_Link_Speed(rpdata->object_instance)); break; + case PROP_LINK_SPEEDS: + count = Network_Port_Link_Speeds_Count(rpdata->object_instance); + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Network_Port_Link_Speeds_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + } + break; case PROP_CHANGES_PENDING: apdu_len = encode_application_boolean(&apdu[0], Network_Port_Changes_Pending(rpdata->object_instance)); @@ -723,6 +776,7 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) case PROP_MAX_APDU_LENGTH_ACCEPTED: case PROP_CHANGES_PENDING: case PROP_APDU_LENGTH: + case PROP_LINK_SPEEDS: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; diff --git a/ports/bdk-atxx4-mstp/Makefile b/ports/bdk-atxx4-mstp/Makefile index 788ae0f3..bd7bf85c 100644 --- a/ports/bdk-atxx4-mstp/Makefile +++ b/ports/bdk-atxx4-mstp/Makefile @@ -223,6 +223,10 @@ BFLAGS += -DBACAPP_ENUMERATED BFLAGS += -DBACAPP_CHARACTER_STRING BFLAGS += -DBACAPP_OCTET_STRING BFLAGS += -DWRITE_PROPERTY +ifeq (${LEGACY},true) +# disable deprecated function warnings for legacy builds +BFLAGS += -DBACNET_STACK_DEPRECATED_DISABLE +endif ## Compile options for C files CFLAGS = $(COMMON) diff --git a/ports/bdk-atxx4-mstp/netport.c b/ports/bdk-atxx4-mstp/netport.c index 3a2899a6..265f7054 100644 --- a/ports/bdk-atxx4-mstp/netport.c +++ b/ports/bdk-atxx4-mstp/netport.c @@ -68,6 +68,10 @@ struct object_data Object_List[BACNET_NETWORK_PORTS_MAX]; #define BACNET_NETWORK_PORT_INSTANCE 1 #endif +/* BACnetARRAY of REAL, is an array of the link speeds + supported by this network port */ +static uint32_t Link_Speeds[] = {9600, 19200, 38400, 57600, 76800, 115200 }; + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_STATUS_FLAGS, PROP_RELIABILITY, @@ -76,7 +80,8 @@ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_APDU_LENGTH, PROP_LINK_SPEED, -1 }; static const int Network_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, - PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, -1 }; + PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_LINK_SPEEDS, + -1 }; static const int Network_Port_Properties_Proprietary[] = { -1 }; @@ -348,6 +353,41 @@ float Network_Port_Link_Speed(uint32_t object_instance) return Object_List[0].Link_Speed; } +/** + * @brief Get the number of Link speeds supported by this object + * @param object_instance [in] BACnet network port object instance number + * @return number of link-speed values supported by this object + */ +static unsigned Network_Port_Link_Speeds_Count(uint32_t object_instance) +{ + return ARRAY_SIZE(Link_Speeds); +} + +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +static int Network_Port_Link_Speeds_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + float link_speed; + + (void)object_instance; + if (array_index < ARRAY_SIZE(Link_Speeds)) { + link_speed = Link_Speeds[array_index]; + apdu_len = encode_application_real(apdu, link_speed); + } + + return apdu_len; +} + /** * @brief Set the device link speed (baud rate) * @param object_instance The object instance number of the object @@ -358,18 +398,16 @@ bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value) { bool status = false; uint32_t baud = (uint32_t)value; + unsigned i; - switch (baud) { - case 9600: - case 19200: - case 38400: - case 57600: - case 76800: - case 115200: + (void)object_instance; + for (i = 0; i < ARRAY_SIZE(Link_Speeds); i++) { + if (Link_Speeds[i] == baud) { Object_List[0].Link_Speed = value; Object_List[0].Changes_Pending = true; status = true; break; + } } return status; @@ -497,17 +535,19 @@ bool Network_Port_MSTP_Max_Info_Frames_Set( */ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { - int apdu_len = 0; + int apdu_len = 0, apdu_max; BACNET_BIT_STRING bit_string; BACNET_OCTET_STRING octet_string; BACNET_CHARACTER_STRING char_string; uint8_t *apdu = NULL; + unsigned count; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -577,6 +617,20 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_real( &apdu[0], Network_Port_Link_Speed(rpdata->object_instance)); break; + case PROP_LINK_SPEEDS: + count = Network_Port_Link_Speeds_Count(rpdata->object_instance); + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Network_Port_Link_Speeds_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + } + break; case PROP_CHANGES_PENDING: apdu_len = encode_application_boolean(&apdu[0], Network_Port_Changes_Pending(rpdata->object_instance)); @@ -723,6 +777,7 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) case PROP_MAX_APDU_LENGTH_ACCEPTED: case PROP_CHANGES_PENDING: case PROP_APDU_LENGTH: + case PROP_LINK_SPEEDS: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; diff --git a/ports/stm32f10x/Makefile b/ports/stm32f10x/Makefile index 4e28d81a..4fc94b09 100644 --- a/ports/stm32f10x/Makefile +++ b/ports/stm32f10x/Makefile @@ -148,6 +148,10 @@ BACNET_FLAGS += -DMAX_OCTET_STRING_BYTES=64 # if called from root Makefile, PRINT was already defined BACNET_FLAGS += -UPRINT_ENABLED BACNET_FLAGS += -DPRINT_ENABLED=0 +ifeq (${LEGACY},true) +# disable deprecated function warnings for legacy builds +BACNET_FLAGS += -DBACNET_STACK_DEPRECATED_DISABLE +endif CFLAGS += $(MCU_FLAGS) CFLAGS += $(OPTIMIZE_FLAGS) diff --git a/ports/stm32f10x/netport.c b/ports/stm32f10x/netport.c index 47896e0b..f0d48ddb 100644 --- a/ports/stm32f10x/netport.c +++ b/ports/stm32f10x/netport.c @@ -47,7 +47,6 @@ /* MS/TP specific */ #include "bacnet/datalink/dlmstp.h" #include "rs485.h" -// #include "nvdata.h" /* me */ #include "bacnet/basic/object/netport.h" @@ -68,6 +67,10 @@ struct object_data Object_List[BACNET_NETWORK_PORTS_MAX]; #define BACNET_NETWORK_PORT_INSTANCE 1 #endif +/* BACnetARRAY of REAL, is an array of the link speeds + supported by this network port */ +static uint32_t Link_Speeds[] = {9600, 19200, 38400, 57600, 76800, 115200 }; + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_STATUS_FLAGS, PROP_RELIABILITY, @@ -76,7 +79,8 @@ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_APDU_LENGTH, PROP_LINK_SPEED, -1 }; static const int Network_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, - PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, -1 }; + PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_LINK_SPEEDS, + -1 }; static const int Network_Port_Properties_Proprietary[] = { -1 }; @@ -348,6 +352,41 @@ float Network_Port_Link_Speed(uint32_t object_instance) return Object_List[0].Link_Speed; } +/** + * @brief Get the number of Link speeds supported by this object + * @param object_instance [in] BACnet network port object instance number + * @return number of link-speed values supported by this object + */ +static unsigned Network_Port_Link_Speeds_Count(uint32_t object_instance) +{ + return ARRAY_SIZE(Link_Speeds); +} + +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +static int Network_Port_Link_Speeds_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + float link_speed; + + (void)object_instance; + if (array_index < ARRAY_SIZE(Link_Speeds)) { + link_speed = Link_Speeds[array_index]; + apdu_len = encode_application_real(apdu, link_speed); + } + + return apdu_len; +} + /** * @brief Set the device link speed (baud rate) * @param object_instance The object instance number of the object @@ -358,20 +397,16 @@ bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value) { bool status = false; uint32_t baud = (uint32_t)value; + unsigned i; - switch (baud) { - case 9600: - case 19200: - case 38400: - case 57600: - case 76800: - case 115200: + (void)object_instance; + for (i = 0; i < ARRAY_SIZE(Link_Speeds); i++) { + if (Link_Speeds[i] == baud) { Object_List[0].Link_Speed = value; Object_List[0].Changes_Pending = true; status = true; break; - default: - break; + } } return status; @@ -499,17 +534,19 @@ bool Network_Port_MSTP_Max_Info_Frames_Set( */ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { - int apdu_len = 0; + int apdu_len = 0, apdu_max; BACNET_BIT_STRING bit_string; BACNET_OCTET_STRING octet_string; BACNET_CHARACTER_STRING char_string; uint8_t *apdu = NULL; + unsigned count; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -579,6 +616,20 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_real( &apdu[0], Network_Port_Link_Speed(rpdata->object_instance)); break; + case PROP_LINK_SPEEDS: + count = Network_Port_Link_Speeds_Count(rpdata->object_instance); + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Network_Port_Link_Speeds_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + } + break; case PROP_CHANGES_PENDING: apdu_len = encode_application_boolean(&apdu[0], Network_Port_Changes_Pending(rpdata->object_instance)); @@ -725,6 +776,7 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) case PROP_MAX_APDU_LENGTH_ACCEPTED: case PROP_CHANGES_PENDING: case PROP_APDU_LENGTH: + case PROP_LINK_SPEEDS: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; diff --git a/ports/stm32f4xx/Makefile b/ports/stm32f4xx/Makefile index b3bb7d72..c5b91112 100644 --- a/ports/stm32f4xx/Makefile +++ b/ports/stm32f4xx/Makefile @@ -145,6 +145,10 @@ BACNET_FLAGS += -DMAX_OCTET_STRING_BYTES=64 # if called from root Makefile, PRINT was already defined BACNET_FLAGS += -UPRINT_ENABLED BACNET_FLAGS += -DPRINT_ENABLED=0 +ifeq (${LEGACY},true) +# disable deprecated function warnings for legacy builds +BACNET_FLAGS += -DBACNET_STACK_DEPRECATED_DISABLE +endif CFLAGS += $(MCU_FLAGS) CFLAGS += $(OPTIMIZE_FLAGS) diff --git a/ports/stm32f4xx/netport.c b/ports/stm32f4xx/netport.c index 3a2899a6..f0d48ddb 100644 --- a/ports/stm32f4xx/netport.c +++ b/ports/stm32f4xx/netport.c @@ -47,7 +47,6 @@ /* MS/TP specific */ #include "bacnet/datalink/dlmstp.h" #include "rs485.h" -//#include "nvdata.h" /* me */ #include "bacnet/basic/object/netport.h" @@ -68,6 +67,10 @@ struct object_data Object_List[BACNET_NETWORK_PORTS_MAX]; #define BACNET_NETWORK_PORT_INSTANCE 1 #endif +/* BACnetARRAY of REAL, is an array of the link speeds + supported by this network port */ +static uint32_t Link_Speeds[] = {9600, 19200, 38400, 57600, 76800, 115200 }; + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_STATUS_FLAGS, PROP_RELIABILITY, @@ -76,7 +79,8 @@ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_APDU_LENGTH, PROP_LINK_SPEED, -1 }; static const int Network_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, - PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, -1 }; + PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_LINK_SPEEDS, + -1 }; static const int Network_Port_Properties_Proprietary[] = { -1 }; @@ -348,6 +352,41 @@ float Network_Port_Link_Speed(uint32_t object_instance) return Object_List[0].Link_Speed; } +/** + * @brief Get the number of Link speeds supported by this object + * @param object_instance [in] BACnet network port object instance number + * @return number of link-speed values supported by this object + */ +static unsigned Network_Port_Link_Speeds_Count(uint32_t object_instance) +{ + return ARRAY_SIZE(Link_Speeds); +} + +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +static int Network_Port_Link_Speeds_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + float link_speed; + + (void)object_instance; + if (array_index < ARRAY_SIZE(Link_Speeds)) { + link_speed = Link_Speeds[array_index]; + apdu_len = encode_application_real(apdu, link_speed); + } + + return apdu_len; +} + /** * @brief Set the device link speed (baud rate) * @param object_instance The object instance number of the object @@ -358,18 +397,16 @@ bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value) { bool status = false; uint32_t baud = (uint32_t)value; + unsigned i; - switch (baud) { - case 9600: - case 19200: - case 38400: - case 57600: - case 76800: - case 115200: + (void)object_instance; + for (i = 0; i < ARRAY_SIZE(Link_Speeds); i++) { + if (Link_Speeds[i] == baud) { Object_List[0].Link_Speed = value; Object_List[0].Changes_Pending = true; status = true; break; + } } return status; @@ -497,17 +534,19 @@ bool Network_Port_MSTP_Max_Info_Frames_Set( */ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { - int apdu_len = 0; + int apdu_len = 0, apdu_max; BACNET_BIT_STRING bit_string; BACNET_OCTET_STRING octet_string; BACNET_CHARACTER_STRING char_string; uint8_t *apdu = NULL; + unsigned count; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -577,6 +616,20 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_real( &apdu[0], Network_Port_Link_Speed(rpdata->object_instance)); break; + case PROP_LINK_SPEEDS: + count = Network_Port_Link_Speeds_Count(rpdata->object_instance); + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Network_Port_Link_Speeds_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + } + break; case PROP_CHANGES_PENDING: apdu_len = encode_application_boolean(&apdu[0], Network_Port_Changes_Pending(rpdata->object_instance)); @@ -723,6 +776,7 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) case PROP_MAX_APDU_LENGTH_ACCEPTED: case PROP_CHANGES_PENDING: case PROP_APDU_LENGTH: + case PROP_LINK_SPEEDS: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; diff --git a/ports/xplained/ASF/xmega/drivers/cpu/ccp.s b/ports/xplained/ASF/xmega/drivers/cpu/ccp.S similarity index 100% rename from ports/xplained/ASF/xmega/drivers/cpu/ccp.s rename to ports/xplained/ASF/xmega/drivers/cpu/ccp.S diff --git a/ports/xplained/ASF/xmega/drivers/nvm/nvm_asm.s b/ports/xplained/ASF/xmega/drivers/nvm/nvm_asm.S similarity index 100% rename from ports/xplained/ASF/xmega/drivers/nvm/nvm_asm.s rename to ports/xplained/ASF/xmega/drivers/nvm/nvm_asm.S diff --git a/ports/xplained/ASF/xmega/drivers/usart/usart.c b/ports/xplained/ASF/xmega/drivers/usart/usart.c index d1ec2e0f..7f0201fc 100644 --- a/ports/xplained/ASF/xmega/drivers/usart/usart.c +++ b/ports/xplained/ASF/xmega/drivers/usart/usart.c @@ -95,7 +95,7 @@ bool usart_init_rs232(USART_t *usart, const usart_rs232_options_t *opt) */ void usart_init_spi(USART_t *usart, const usart_spi_options_t *opt) { - ioport_pin_t sck_pin; + ioport_pin_t sck_pin = UINT8_MAX; bool invert_sck; sysclk_enable_peripheral_clock(usart); @@ -179,6 +179,9 @@ void usart_init_spi(USART_t *usart, const usart_spi_options_t *opt) } #endif + if (sck_pin == UINT8_MAX) { + return; + } /* Configure the USART output pin */ ioport_set_pin_dir(sck_pin, IOPORT_DIR_OUTPUT); ioport_set_pin_mode(sck_pin, diff --git a/ports/xplained/Makefile b/ports/xplained/Makefile index fed36a2b..83671986 100644 --- a/ports/xplained/Makefile +++ b/ports/xplained/Makefile @@ -6,13 +6,30 @@ MCU = atxmega256a3bu TARGET = bacnet ## Tools -#Set the toolchain command names (only the ones needed are defined) -PREFIX ?= "C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-" +# Choose a BACnet Ports Directory for the example applications target OS +ifeq (${PREFIX},) + ifeq ($(OS),Windows_NT) + PREFIX := "C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-" + else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + PREFIX := avr- + endif + ifeq ($(UNAME_S),Darwin) + PREFIX := avr- + endif + endif +endif +#Set the toolchain command names (only the ones needed are defined) CC = $(PREFIX)gcc OBJCOPY = $(PREFIX)objcopy OBJDUMP = $(PREFIX)objdump AR = $(PREFIX)ar +AS = $(PREFIX)as +LD = $(PREFIX)ld +NM = $(PREFIX)nm +STRIP = $(PREFIX)strip SIZE = $(PREFIX)size # Source locations @@ -25,27 +42,33 @@ BACNET_BASIC = $(BACNET_CORE)/basic CSRC = main.c \ adc-hdw.c \ ai.c \ - mstimer-init.c \ + bacnet.c \ + bname.c \ device.c \ dlmstp.c \ + led.c \ + mstimer-init.c \ netport.c \ - stack.c \ + nvmdata.c \ rs485.c \ - led.c + stack.c # common demo files needed BASICSRC = $(BACNET_BASIC)/tsm/tsm.c \ $(BACNET_BASIC)/sys/bigend.c \ + $(BACNET_BASIC)/sys/debug.c \ $(BACNET_BASIC)/sys/fifo.c \ $(BACNET_BASIC)/sys/ringbuf.c \ $(BACNET_BASIC)/sys/mstimer.c \ $(BACNET_BASIC)/npdu/h_npdu.c \ $(BACNET_BASIC)/service/h_apdu.c \ + $(BACNET_BASIC)/service/h_dcc.c \ $(BACNET_BASIC)/service/h_rd.c \ $(BACNET_BASIC)/service/h_rp.c \ $(BACNET_BASIC)/service/h_rpm.c \ $(BACNET_BASIC)/service/h_whois.c \ $(BACNET_BASIC)/service/h_whohas.c \ + $(BACNET_BASIC)/service/h_wp.c \ $(BACNET_BASIC)/service/s_cov.c \ $(BACNET_BASIC)/service/s_iam.c \ $(BACNET_BASIC)/service/s_ihave.c \ @@ -92,7 +115,6 @@ SDK_CSRC = \ $(SDK_DIR)/xmega/drivers/adc/adc.c \ $(SDK_DIR)/xmega/drivers/adc/xmega_aau/adc_aau.c \ $(SDK_DIR)/xmega/drivers/rtc32/rtc32.c \ - $(SDK_DIR)/xmega/drivers/tc/tc.c \ $(SDK_DIR)/common/drivers/nvm/xmega/xmega_nvm.c \ $(SDK_DIR)/common/services/serial/usart_serial.c \ $(SDK_DIR)/common/utils/stdio/read.c \ @@ -104,8 +126,8 @@ SDK_CSRC = \ $(SDK_DIR)/xmega/services/timeout/timeout.c SDK_ASRC = \ - $(SDK_DIR)/xmega/drivers/cpu/ccp.s \ - $(SDK_DIR)/xmega/drivers/nvm/nvm_asm.s + $(SDK_DIR)/xmega/drivers/cpu/ccp.S \ + $(SDK_DIR)/xmega/drivers/nvm/nvm_asm.S ## Include Directories SDK_INCLUDES = -I$(SDK_DIR)/xmega/drivers/rtc32 @@ -142,7 +164,7 @@ COBJ = $(CSRC:.c=.o) BASICOBJ = $(BASICSRC:.c=.o) COREOBJ = $(CORESRC:.c=.o) SDK_COBJ = $(SDK_CSRC:.c=.o) -SDK_AOBJ = $(SDK_ASRC:.s=.o) +SDK_AOBJ = $(SDK_ASRC:.S=.o) LIBRARY = lib$(TARGET).a @@ -159,6 +181,11 @@ BFLAGS += -DMSTP_PDU_PACKET_COUNT=2 BFLAGS += -DMAX_ADDRESS_CACHE=32 BFLAGS += -DMAX_ANALOG_INPUTS=8 BFLAGS += -DBACNET_PROTOCOL_REVISION=9 +BFLAGS += -DBACAPP_MINIMAL +ifeq (${LEGACY},true) +# disable deprecated function warnings for legacy builds +BFLAGS += -DBACNET_STACK_DEPRECATED_DISABLE +endif CFLAGS = $(SDK_FLAGS) # dead code removal @@ -177,7 +204,9 @@ CFLAGS += -DIOPORT_XMEGA_COMPAT CFLAGS += -Wno-switch ## Assembly specific flags -AFLAGS = -Wa,-gdwarf2 +AFLAGS = $(SDK_FLAGS) +AFLAGS += $(SDK_INCLUDES) +AFLAGS += -Wa,-gdwarf2 ## Linker flags LDFLAGS = $(SDK_FLAGS) @@ -220,8 +249,8 @@ $(LIBRARY): $(COREOBJ) Makefile .c.o: $(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@ -.s.o: - $(CC) -c $(AFLAGS) $*.s -o $@ +.S.o: + $(CC) -c $(AFLAGS) $*.S -o $@ size: ${TARGET_ELF} @echo diff --git a/ports/xplained/device.c b/ports/xplained/device.c index 319127ea..363143a5 100644 --- a/ports/xplained/device.c +++ b/ports/xplained/device.c @@ -615,8 +615,8 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) uint32_t i = 0; uint32_t count = 0; uint8_t *apdu = NULL; - int apdu_len = 0; struct my_object_functions *pObject = NULL; + int apdu_max; if ((rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { diff --git a/ports/xplained/mstimer-init.c b/ports/xplained/mstimer-init.c index 0c93e512..cf03069f 100644 --- a/ports/xplained/mstimer-init.c +++ b/ports/xplained/mstimer-init.c @@ -44,17 +44,17 @@ static volatile uint32_t Millisecond_Counter; /** - * Handles an interrupt from a hardware millisecond timer + * Handles an interrupt from a hardware counter timer, every millisecond */ -static void my_counter_handler(void) +static void mstimer_counter_handler(void) { Millisecond_Counter++; } /** - * Handles an interrupt from a hardware millisecond timer + * Handles an interrupt from an overflow hardware timer, every millisecond */ -static void my_callback_handler(void) +static void mstimer_overflow_handler(void) { /* callback might go too long; prevent re-entrency by disable IRQ source */ tc_set_overflow_interrupt_level(&MS_TIMER_CALLBACK, TC_INT_LVL_OFF); @@ -98,7 +98,7 @@ void mstimer_init(void) tc_enable(&MS_TIMER_CALLBACK); tc_set_overflow_interrupt_callback(&MS_TIMER_CALLBACK, - my_callback_handler); + mstimer_overflow_handler); tc_set_wgm(&MS_TIMER_CALLBACK, TC_WG_NORMAL); tc_write_count(&MS_TIMER_CALLBACK, 1); period = sysclk_get_peripheral_bus_hz(&MS_TIMER_CALLBACK); diff --git a/ports/xplained/netport.c b/ports/xplained/netport.c index 3a2899a6..f0d48ddb 100644 --- a/ports/xplained/netport.c +++ b/ports/xplained/netport.c @@ -47,7 +47,6 @@ /* MS/TP specific */ #include "bacnet/datalink/dlmstp.h" #include "rs485.h" -//#include "nvdata.h" /* me */ #include "bacnet/basic/object/netport.h" @@ -68,6 +67,10 @@ struct object_data Object_List[BACNET_NETWORK_PORTS_MAX]; #define BACNET_NETWORK_PORT_INSTANCE 1 #endif +/* BACnetARRAY of REAL, is an array of the link speeds + supported by this network port */ +static uint32_t Link_Speeds[] = {9600, 19200, 38400, 57600, 76800, 115200 }; + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_STATUS_FLAGS, PROP_RELIABILITY, @@ -76,7 +79,8 @@ static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_APDU_LENGTH, PROP_LINK_SPEED, -1 }; static const int Network_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, - PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, -1 }; + PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_LINK_SPEEDS, + -1 }; static const int Network_Port_Properties_Proprietary[] = { -1 }; @@ -348,6 +352,41 @@ float Network_Port_Link_Speed(uint32_t object_instance) return Object_List[0].Link_Speed; } +/** + * @brief Get the number of Link speeds supported by this object + * @param object_instance [in] BACnet network port object instance number + * @return number of link-speed values supported by this object + */ +static unsigned Network_Port_Link_Speeds_Count(uint32_t object_instance) +{ + return ARRAY_SIZE(Link_Speeds); +} + +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +static int Network_Port_Link_Speeds_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + float link_speed; + + (void)object_instance; + if (array_index < ARRAY_SIZE(Link_Speeds)) { + link_speed = Link_Speeds[array_index]; + apdu_len = encode_application_real(apdu, link_speed); + } + + return apdu_len; +} + /** * @brief Set the device link speed (baud rate) * @param object_instance The object instance number of the object @@ -358,18 +397,16 @@ bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value) { bool status = false; uint32_t baud = (uint32_t)value; + unsigned i; - switch (baud) { - case 9600: - case 19200: - case 38400: - case 57600: - case 76800: - case 115200: + (void)object_instance; + for (i = 0; i < ARRAY_SIZE(Link_Speeds); i++) { + if (Link_Speeds[i] == baud) { Object_List[0].Link_Speed = value; Object_List[0].Changes_Pending = true; status = true; break; + } } return status; @@ -497,17 +534,19 @@ bool Network_Port_MSTP_Max_Info_Frames_Set( */ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { - int apdu_len = 0; + int apdu_len = 0, apdu_max; BACNET_BIT_STRING bit_string; BACNET_OCTET_STRING octet_string; BACNET_CHARACTER_STRING char_string; uint8_t *apdu = NULL; + unsigned count; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -577,6 +616,20 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_real( &apdu[0], Network_Port_Link_Speed(rpdata->object_instance)); break; + case PROP_LINK_SPEEDS: + count = Network_Port_Link_Speeds_Count(rpdata->object_instance); + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Network_Port_Link_Speeds_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + } + break; case PROP_CHANGES_PENDING: apdu_len = encode_application_boolean(&apdu[0], Network_Port_Changes_Pending(rpdata->object_instance)); @@ -723,6 +776,7 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) case PROP_MAX_APDU_LENGTH_ACCEPTED: case PROP_CHANGES_PENDING: case PROP_APDU_LENGTH: + case PROP_LINK_SPEEDS: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; diff --git a/src/bacnet/basic/object/netport.c b/src/bacnet/basic/object/netport.c index 14b58b0b..d128e3ed 100644 --- a/src/bacnet/basic/object/netport.c +++ b/src/bacnet/basic/object/netport.c @@ -750,8 +750,7 @@ float Network_Port_Link_Speed(uint32_t object_instance) * For a given object instance-number, sets the Link_Speed * * @param object_instance - object-instance number of the object - * @param value - APDU length 0..65535 - * + * @param value Link_Speed value in bits-per-second * @return true if values are within range and property is set. */ bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value) diff --git a/src/bacnet/config.h b/src/bacnet/config.h index 883e2a35..f72c06de 100644 --- a/src/bacnet/config.h +++ b/src/bacnet/config.h @@ -171,6 +171,7 @@ #define BACAPP_SIGNED #define BACAPP_REAL #define BACAPP_CHARACTER_STRING +#define BACAPP_OCTET_STRING #define BACAPP_BIT_STRING #define BACAPP_ENUMERATED #define BACAPP_DATE