From d1361b128b6c7baa8aaff178348fb8d2dd7303b8 Mon Sep 17 00:00:00 2001 From: Ryan Mulder Date: Mon, 23 Jun 2025 18:08:22 -0400 Subject: [PATCH] enable writing mstp mac address and link speed via network_port (#1025) --- src/bacnet/basic/object/device.c | 6 ++ src/bacnet/basic/object/netport.c | 117 ++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/src/bacnet/basic/object/device.c b/src/bacnet/basic/object/device.c index 6309bd81..48022009 100644 --- a/src/bacnet/basic/object/device.c +++ b/src/bacnet/basic/object/device.c @@ -756,6 +756,12 @@ BACNET_REINITIALIZED_STATE Device_Reinitialized_State(void) return Reinitialize_State; } +bool Device_Reinitialize_State_Set(BACNET_REINITIALIZED_STATE state) +{ + Reinitialize_State = state; + return true; +} + unsigned Device_Count(void) { return 1; diff --git a/src/bacnet/basic/object/netport.c b/src/bacnet/basic/object/netport.c index 97e2b6e4..9f43cf0a 100644 --- a/src/bacnet/basic/object/netport.c +++ b/src/bacnet/basic/object/netport.c @@ -125,6 +125,10 @@ struct object_data { static struct object_data Object_List[BACNET_NETWORK_PORTS_MAX]; +/* 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[] = { /* unordered list of required properties */ @@ -170,6 +174,7 @@ static const int MSTP_Port_Properties_Optional[] = { PROP_NETWORK_NUMBER, PROP_NETWORK_NUMBER_QUALITY, PROP_LINK_SPEED, + PROP_LINK_SPEEDS, #endif -1 }; @@ -963,6 +968,7 @@ bool Network_Port_MAC_Address_Set( break; } if (mac_src && mac_dest && (mac_len == mac_size)) { + Object_List[index].Changes_Pending = true; memcpy(mac_dest, mac_src, mac_size); status = true; } @@ -1035,6 +1041,64 @@ float Network_Port_Link_Speed(uint32_t object_instance) return value; } +/** + * @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) +{ + (void)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 = (float)Link_Speeds[array_index]; + apdu_len = encode_application_real(apdu, link_speed); + } + + return apdu_len; +} + +/** + * Validate the Link_Speed + * + * @param value Link_Speed value in bits-per-second + * @return true if values are in Link_Speeds + */ +static bool Network_Port_Link_Speed_Valid(const float value) +{ + bool status = false; + uint32_t baud = (uint32_t)value; + unsigned i; + + for (i = 0; i < ARRAY_SIZE(Link_Speeds); i++) { + if (Link_Speeds[i] == baud) { + status = true; + break; + } + } + + return status; +} + /** * For a given object instance-number, sets the Link_Speed * @@ -1050,6 +1114,7 @@ bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value) index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { Object_List[index].Link_Speed = value; + Object_List[index].Changes_Pending = true; status = true; } @@ -3861,6 +3926,7 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) 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)) { @@ -3946,6 +4012,19 @@ 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_size); + 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], @@ -4337,6 +4416,24 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) } /* FIXME: len < application_data_len: more data? */ switch (wp_data->object_property) { + case PROP_MAC_ADDRESS: + if (Network_Port_Type(wp_data->object_instance) == PORT_TYPE_MSTP) { + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_OCTET_STRING); + if (status) { + status = Network_Port_MAC_Address_Set( + wp_data->object_instance, value.type.Octet_String.value, + value.type.Octet_String.length); + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } + break; case PROP_MAX_MASTER: status = write_property_type_valid( wp_data, &value, BACNET_APPLICATION_TAG_UNSIGNED_INT); @@ -4372,6 +4469,26 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) } } break; + case PROP_LINK_SPEED: + if (Network_Port_Type(wp_data->object_instance) == PORT_TYPE_MSTP) { + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_REAL); + if (status) { + status = Network_Port_Link_Speed_Valid(value.type.Real); + if (status) { + status = Network_Port_Link_Speed_Set( + wp_data->object_instance, value.type.Real); + } + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } + break; case PROP_FD_BBMD_ADDRESS: if (write_property_type_valid( wp_data, &value, BACNET_APPLICATION_TAG_HOST_N_PORT)) {