Added _Address versions of a few services, primarily for interacting with MS/TP slaves (#1174)

* add address versions of Send_Write_Property_Request and Send_Read_Property_Multiple_Request

* add Send_COV_Subscribe_Address
This commit is contained in:
Ryan Mulder
2025-12-03 17:05:26 -05:00
committed by GitHub
parent 6993a7c0fd
commit 9a335b545e
6 changed files with 221 additions and 58 deletions
+35 -14
View File
@@ -90,19 +90,19 @@ int Send_UCOV_Notify(
/** Sends a COV Subscription request.
* @ingroup DSCOV
*
* @param device_id [in] ID of the destination device
* @param dest [in] BACNET_ADDRESS of the destination device
* @param max_apdu [in]
* @param cov_data [in] The COV subscription information to be encoded.
* @return invoke id of outgoing message, or 0 if communication is disabled or
* no slot is available from the tsm for sending.
*/
uint8_t Send_COV_Subscribe(
uint32_t device_id, const BACNET_SUBSCRIBE_COV_DATA *cov_data)
uint8_t Send_COV_Subscribe_Address(
BACNET_ADDRESS *dest,
uint16_t max_apdu,
const BACNET_SUBSCRIBE_COV_DATA *cov_data)
{
BACNET_ADDRESS dest;
BACNET_ADDRESS my_address;
unsigned max_apdu = 0;
uint8_t invoke_id = 0;
bool status = false;
int len = 0;
int pdu_len = 0;
int bytes_sent = 0;
@@ -111,18 +111,14 @@ uint8_t Send_COV_Subscribe(
if (!dcc_communication_enabled()) {
return 0;
}
/* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */
if (status) {
invoke_id = tsm_next_free_invokeID();
}
invoke_id = tsm_next_free_invokeID();
if (invoke_id) {
/* encode the NPDU portion of the packet */
datalink_get_my_address(&my_address);
npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
pdu_len = npdu_encode_pdu(
&Handler_Transmit_Buffer[0], &dest, &my_address, &npdu_data);
&Handler_Transmit_Buffer[0], dest, &my_address, &npdu_data);
/* encode the APDU portion of the packet */
if (cov_data->covSubscribeToProperty) {
/* subscribe to 1 property */
@@ -143,10 +139,10 @@ uint8_t Send_COV_Subscribe(
max_apdu in the address binding table. */
if ((unsigned)pdu_len < max_apdu) {
tsm_set_confirmed_unsegmented_transaction(
invoke_id, &dest, &npdu_data, &Handler_Transmit_Buffer[0],
invoke_id, dest, &npdu_data, &Handler_Transmit_Buffer[0],
(uint16_t)pdu_len);
bytes_sent = datalink_send_pdu(
&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
if (bytes_sent <= 0) {
debug_perror("Failed to Send SubscribeCOV Request");
}
@@ -162,3 +158,28 @@ uint8_t Send_COV_Subscribe(
return invoke_id;
}
/** Sends a COV Subscription request.
* @ingroup DSCOV
*
* @param device_id [in] ID of the destination device
* @param cov_data [in] The COV subscription information to be encoded.
* @return invoke id of outgoing message, or 0 if communication is disabled or
* no slot is available from the tsm for sending.
*/
uint8_t Send_COV_Subscribe(
uint32_t device_id, const BACNET_SUBSCRIBE_COV_DATA *cov_data)
{
BACNET_ADDRESS dest = { 0 };
unsigned max_apdu = 0;
uint8_t invoke_id = 0;
bool status = false;
/* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest);
if (status) {
invoke_id = Send_COV_Subscribe_Address(&dest, max_apdu, cov_data);
}
return invoke_id;
}
+5
View File
@@ -39,6 +39,11 @@ int ucov_notify_encode_pdu(
BACNET_NPDU_DATA *npdu_data,
const BACNET_COV_DATA *cov_data);
BACNET_STACK_EXPORT
uint8_t Send_COV_Subscribe_Address(
BACNET_ADDRESS *dest,
uint16_t max_apdu,
const BACNET_SUBSCRIBE_COV_DATA *cov_data);
BACNET_STACK_EXPORT
uint8_t Send_COV_Subscribe(
uint32_t device_id, const BACNET_SUBSCRIBE_COV_DATA *cov_data);
+41 -14
View File
@@ -27,6 +27,8 @@
/**
* @brief Sends a Read Property Multiple request.
* @ingroup BIBB-DS-RPM-A
* @param dest [in] BACNET_ADDRESS of the destination device
* @param max_apdu [in]
* @param pdu [out] Buffer to build the outgoing message into
* @param max_pdu [in] Length of the pdu buffer.
* @param device_id [in] ID of the destination device
@@ -35,17 +37,16 @@
* @return invoke id of outgoing message, or 0 if device is not bound or no tsm
* available
*/
uint8_t Send_Read_Property_Multiple_Request(
BACNET_STACK_EXPORT
uint8_t Send_Read_Property_Multiple_Request_Address(
BACNET_ADDRESS *dest,
uint16_t max_apdu,
uint8_t *pdu,
size_t max_pdu,
uint32_t device_id, /* destination device */
BACNET_READ_ACCESS_DATA *read_access_data)
{
BACNET_ADDRESS dest;
BACNET_ADDRESS my_address;
unsigned max_apdu = 0;
uint8_t invoke_id = 0;
bool status = false;
int len = 0;
int pdu_len = 0;
int bytes_sent = 0;
@@ -54,17 +55,12 @@ uint8_t Send_Read_Property_Multiple_Request(
if (!dcc_communication_enabled()) {
return 0;
}
/* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */
if (status) {
invoke_id = tsm_next_free_invokeID();
}
invoke_id = tsm_next_free_invokeID();
if (invoke_id) {
/* encode the NPDU portion of the packet */
datalink_get_my_address(&my_address);
npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
pdu_len = npdu_encode_pdu(&pdu[0], &dest, &my_address, &npdu_data);
pdu_len = npdu_encode_pdu(&pdu[0], dest, &my_address, &npdu_data);
/* encode the APDU portion of the packet */
len = rpm_encode_apdu(
&pdu[pdu_len], max_pdu - pdu_len, invoke_id, read_access_data);
@@ -79,8 +75,8 @@ uint8_t Send_Read_Property_Multiple_Request(
max_apdu in the address binding table. */
if ((unsigned)pdu_len < max_apdu) {
tsm_set_confirmed_unsegmented_transaction(
invoke_id, &dest, &npdu_data, &pdu[0], (uint16_t)pdu_len);
bytes_sent = datalink_send_pdu(&dest, &npdu_data, &pdu[0], pdu_len);
invoke_id, dest, &npdu_data, &pdu[0], (uint16_t)pdu_len);
bytes_sent = datalink_send_pdu(dest, &npdu_data, &pdu[0], pdu_len);
if (bytes_sent <= 0) {
debug_perror("Failed to Send ReadPropertyMultiple Request");
}
@@ -96,3 +92,34 @@ uint8_t Send_Read_Property_Multiple_Request(
return invoke_id;
}
/**
* @brief Sends a Read Property Multiple request.
* @ingroup BIBB-DS-RPM-A
* @param pdu [out] Buffer to build the outgoing message into
* @param max_pdu [in] Length of the pdu buffer.
* @param device_id [in] ID of the destination device
* @param read_access_data [in] Ptr to structure with the linked list of
* properties to be read.
* @return invoke id of outgoing message, or 0 if device is not bound or no tsm
* available
*/
uint8_t Send_Read_Property_Multiple_Request(
uint8_t *pdu,
size_t max_pdu,
uint32_t device_id, /* destination device */
BACNET_READ_ACCESS_DATA *read_access_data)
{
BACNET_ADDRESS dest = { 0 };
unsigned max_apdu = 0;
uint8_t invoke_id = 0;
bool status = false;
/* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest);
if (status) {
invoke_id = Send_Read_Property_Multiple_Request_Address(
&dest, max_apdu, pdu, max_pdu, read_access_data);
}
return invoke_id;
}
+7
View File
@@ -26,6 +26,13 @@
extern "C" {
#endif /* __cplusplus */
BACNET_STACK_EXPORT
uint8_t Send_Read_Property_Multiple_Request_Address(
BACNET_ADDRESS *dest,
uint16_t max_apdu,
uint8_t *pdu,
size_t max_pdu,
BACNET_READ_ACCESS_DATA *read_access_data);
BACNET_STACK_EXPORT
uint8_t Send_Read_Property_Multiple_Request(
uint8_t *pdu,
+112 -30
View File
@@ -31,8 +31,9 @@
* @param data [in] The data representing the Life Safety Operation
* @return invoke id of outgoing message, or zero on failure.
*/
uint8_t Send_Write_Property_Request_Data(
uint32_t device_id,
uint8_t Send_Write_Property_Request_Data_Address(
BACNET_ADDRESS *dest,
uint16_t max_apdu,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_ID object_property,
@@ -41,11 +42,8 @@ uint8_t Send_Write_Property_Request_Data(
uint8_t priority,
uint32_t array_index)
{
BACNET_ADDRESS dest;
BACNET_ADDRESS my_address;
unsigned max_apdu = 0;
uint8_t invoke_id = 0;
bool status = false;
int len = 0;
int pdu_len = 0;
int bytes_sent = 0;
@@ -55,18 +53,14 @@ uint8_t Send_Write_Property_Request_Data(
if (!dcc_communication_enabled()) {
return 0;
}
/* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */
if (status) {
invoke_id = tsm_next_free_invokeID();
}
invoke_id = tsm_next_free_invokeID();
if (invoke_id) {
/* encode the NPDU portion of the packet */
datalink_get_my_address(&my_address);
npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
pdu_len = npdu_encode_pdu(
&Handler_Transmit_Buffer[0], &dest, &my_address, &npdu_data);
&Handler_Transmit_Buffer[0], dest, &my_address, &npdu_data);
/* encode the APDU portion of the packet */
data.object_type = object_type;
data.object_instance = object_instance;
@@ -87,10 +81,10 @@ uint8_t Send_Write_Property_Request_Data(
max_apdu in the address binding table. */
if ((unsigned)pdu_len < max_apdu) {
tsm_set_confirmed_unsegmented_transaction(
invoke_id, &dest, &npdu_data, &Handler_Transmit_Buffer[0],
invoke_id, dest, &npdu_data, &Handler_Transmit_Buffer[0],
(uint16_t)pdu_len);
bytes_sent = datalink_send_pdu(
&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
if (bytes_sent <= 0) {
debug_perror("Failed to Send WriteProperty Request");
}
@@ -106,6 +100,107 @@ uint8_t Send_Write_Property_Request_Data(
return invoke_id;
}
/**
* @brief Send a WriteProperty-Request service message
* @ingroup BIBB-DS-WP-A
* @param device_id [in] ID of the destination device
* @param data [in] The data representing the Life Safety Operation
* @return invoke id of outgoing message, or zero on failure.
*/
uint8_t Send_Write_Property_Request_Data(
uint32_t device_id,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_ID object_property,
const uint8_t *application_data,
int application_data_len,
uint8_t priority,
uint32_t array_index)
{
BACNET_ADDRESS dest = { 0 };
unsigned max_apdu = 0;
uint8_t invoke_id = 0;
bool status = false;
/* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest);
if (status) {
invoke_id = Send_Write_Property_Request_Data_Address(
&dest, max_apdu, object_type, object_instance, object_property,
application_data, application_data_len, priority, array_index);
}
return invoke_id;
}
/**
* @brief Encode the object_value and store it into application_data.
* @param application_data Buffer to store the encoded data
* only
* @param object_value Pointer to the application value structure
* @return Length of the encoded data in bytes, or 0 if it does not fit in
* application_data
*/
static int encode_object_value(
const BACNET_APPLICATION_DATA_VALUE *object_value,
uint8_t *application_data,
const int application_data_len)
{
int apdu_len = 0, len = 0;
while (object_value) {
debug_printf(
"WriteProperty service: "
"%s tag=%d\n",
(object_value->context_specific ? "context" : "application"),
(int)(object_value->context_specific ? object_value->context_tag
: object_value->tag));
len = bacapp_encode_data(&application_data[apdu_len], object_value);
if ((len + apdu_len) < application_data_len) {
apdu_len += len;
} else {
return 0;
}
object_value = object_value->next;
}
return apdu_len;
}
/**
* @brief Sends a Write Property request.
* @ingroup BIBB-DS-WP-A
* @param device_id [in] ID of the destination device
* @param object_type [in] Type of the object whose property is to be written.
* @param object_instance [in] Instance # of the object to be written.
* @param object_property [in] Property to be written.
* @param object_value [in] The value to be written to the property.
* @param priority [in] Write priority of 1 (highest) to 16 (lowest)
* @param array_index [in] Optional: if the Property is an array,
* - 0 for the array size
* - 1 to n for individual array members
* - BACNET_ARRAY_ALL (~0) for the array value to be ignored (not sent)
* @return invoke id of outgoing message, or 0 on failure.
*/
BACNET_STACK_EXPORT
uint8_t Send_Write_Property_Request_Address(
BACNET_ADDRESS *dest,
uint16_t max_apdu,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_ID object_property,
const BACNET_APPLICATION_DATA_VALUE *object_value,
uint8_t priority,
uint32_t array_index)
{
uint8_t application_data[MAX_APDU] = { 0 };
int apdu_len = 0;
apdu_len = encode_object_value(
object_value, application_data, sizeof application_data);
return Send_Write_Property_Request_Data_Address(
dest, max_apdu, object_type, object_instance, object_property,
&application_data[0], apdu_len, priority, array_index);
}
/**
* @brief Sends a Write Property request.
@@ -132,23 +227,10 @@ uint8_t Send_Write_Property_Request(
uint32_t array_index)
{
uint8_t application_data[MAX_APDU] = { 0 };
int apdu_len = 0, len = 0;
int apdu_len = 0;
while (object_value) {
debug_printf(
"WriteProperty service: "
"%s tag=%d\n",
(object_value->context_specific ? "context" : "application"),
(int)(object_value->context_specific ? object_value->context_tag
: object_value->tag));
len = bacapp_encode_data(&application_data[apdu_len], object_value);
if ((len + apdu_len) < MAX_APDU) {
apdu_len += len;
} else {
return 0;
}
object_value = object_value->next;
}
apdu_len = encode_object_value(
object_value, application_data, sizeof application_data);
return Send_Write_Property_Request_Data(
device_id, object_type, object_instance, object_property,
+21
View File
@@ -25,6 +25,16 @@
extern "C" {
#endif /* __cplusplus */
BACNET_STACK_EXPORT
uint8_t Send_Write_Property_Request_Address(
BACNET_ADDRESS *dest,
uint16_t max_apdu,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_ID object_property,
const BACNET_APPLICATION_DATA_VALUE *object_value,
uint8_t priority,
uint32_t array_index);
BACNET_STACK_EXPORT
uint8_t Send_Write_Property_Request(
uint32_t device_id, /* destination device */
@@ -35,6 +45,17 @@ uint8_t Send_Write_Property_Request(
uint8_t priority,
uint32_t array_index);
BACNET_STACK_EXPORT
uint8_t Send_Write_Property_Request_Data_Address(
BACNET_ADDRESS *dest,
uint16_t max_apdu,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_ID object_property,
const uint8_t *application_data,
int application_data_len,
uint8_t priority,
uint32_t array_index);
BACNET_STACK_EXPORT
uint8_t Send_Write_Property_Request_Data(
uint32_t device_id,
BACNET_OBJECT_TYPE object_type,