Optimize COV Subscriptions using keylist (#1295)
* Added performance optimization in COV Subscriptions using keylist * Add memory exhaustion check to Keylist_Data_Add, fix CheckArraySize return value - Keylist_Data_Add: return -1 when node allocation fails - CheckArraySize: return false instead of true when calloc fails (typo)
This commit is contained in:
+184
-137
@@ -6,6 +6,7 @@
|
|||||||
* @copyright SPDX-License-Identifier: MIT
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
#include "bacnet/basic/tsm/tsm.h"
|
#include "bacnet/basic/tsm/tsm.h"
|
||||||
#include "bacnet/basic/object/device.h"
|
#include "bacnet/basic/object/device.h"
|
||||||
#include "bacnet/basic/services.h"
|
#include "bacnet/basic/services.h"
|
||||||
|
#include "bacnet/basic/sys/keylist.h"
|
||||||
#include "bacnet/basic/sys/debug.h"
|
#include "bacnet/basic/sys/debug.h"
|
||||||
#include "bacnet/datalink/datalink.h"
|
#include "bacnet/datalink/datalink.h"
|
||||||
|
|
||||||
@@ -43,7 +45,6 @@ typedef struct BACnet_COV_Address {
|
|||||||
/* note: This COV service only monitors the properties
|
/* note: This COV service only monitors the properties
|
||||||
of an object that have been specified in the standard. */
|
of an object that have been specified in the standard. */
|
||||||
typedef struct BACnet_COV_Subscription_Flags {
|
typedef struct BACnet_COV_Subscription_Flags {
|
||||||
bool valid : 1;
|
|
||||||
bool issueConfirmedNotifications : 1; /* optional */
|
bool issueConfirmedNotifications : 1; /* optional */
|
||||||
bool send_requested : 1;
|
bool send_requested : 1;
|
||||||
} BACNET_COV_SUBSCRIPTION_FLAGS;
|
} BACNET_COV_SUBSCRIPTION_FLAGS;
|
||||||
@@ -57,12 +58,11 @@ typedef struct BACnet_COV_Subscription {
|
|||||||
BACNET_OBJECT_ID monitoredObjectIdentifier;
|
BACNET_OBJECT_ID monitoredObjectIdentifier;
|
||||||
} BACNET_COV_SUBSCRIPTION;
|
} BACNET_COV_SUBSCRIPTION;
|
||||||
|
|
||||||
#ifndef MAX_COV_SUBCRIPTIONS
|
#ifndef MAX_COV_SUBSCRIPTIONS
|
||||||
#define MAX_COV_SUBCRIPTIONS 128
|
#define MAX_COV_SUBSCRIPTIONS 128
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static BACNET_COV_SUBSCRIPTION COV_Subscriptions_List[MAX_NUM_DEVICES]
|
static OS_Keylist COV_Subscriptions_List[MAX_NUM_DEVICES];
|
||||||
[MAX_COV_SUBCRIPTIONS];
|
|
||||||
#ifdef BAC_ROUTING
|
#ifdef BAC_ROUTING
|
||||||
#define COV_Subscriptions (COV_Subscriptions_List[Routed_Device_Object_Index()])
|
#define COV_Subscriptions (COV_Subscriptions_List[Routed_Device_Object_Index()])
|
||||||
#else
|
#else
|
||||||
@@ -73,6 +73,53 @@ static BACNET_COV_SUBSCRIPTION COV_Subscriptions_List[MAX_NUM_DEVICES]
|
|||||||
#endif
|
#endif
|
||||||
static BACNET_COV_ADDRESS COV_Addresses[MAX_COV_ADDRESSES];
|
static BACNET_COV_ADDRESS COV_Addresses[MAX_COV_ADDRESSES];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deletes a subscription
|
||||||
|
* @param list_idx - keylist index
|
||||||
|
* @return true if the subscription was deleted
|
||||||
|
*/
|
||||||
|
static bool cov_subscription_delete(uint32_t list_idx)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
BACNET_COV_SUBSCRIPTION *subscription = NULL;
|
||||||
|
|
||||||
|
subscription = Keylist_Data_Delete_By_Index(COV_Subscriptions, list_idx);
|
||||||
|
if (subscription) {
|
||||||
|
free(subscription);
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a subscription
|
||||||
|
* @param list_key - keylist key
|
||||||
|
* @return the subscription that was created, or NULL
|
||||||
|
*/
|
||||||
|
static BACNET_COV_SUBSCRIPTION *cov_subscription_create(uint32_t list_key)
|
||||||
|
{
|
||||||
|
BACNET_COV_SUBSCRIPTION *subscription = NULL;
|
||||||
|
int index = 0;
|
||||||
|
if (list_key >= MAX_COV_SUBSCRIPTIONS) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
subscription = Keylist_Data(COV_Subscriptions, list_key);
|
||||||
|
if (!subscription) {
|
||||||
|
subscription = calloc(1, sizeof(BACNET_COV_SUBSCRIPTION));
|
||||||
|
if (subscription) {
|
||||||
|
index = Keylist_Data_Add(COV_Subscriptions, list_key, subscription);
|
||||||
|
if (index < 0) {
|
||||||
|
free(subscription);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the address from the list of COV addresses
|
* Gets the address from the list of COV addresses
|
||||||
*
|
*
|
||||||
@@ -103,6 +150,7 @@ static void cov_address_remove_unused(void)
|
|||||||
unsigned index = 0;
|
unsigned index = 0;
|
||||||
unsigned cov_index = 0;
|
unsigned cov_index = 0;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
BACNET_COV_SUBSCRIPTION *subscription = NULL;
|
||||||
|
|
||||||
#ifdef BAC_ROUTING
|
#ifdef BAC_ROUTING
|
||||||
uint16_t current_dev_id = Routed_Device_Object_Index();
|
uint16_t current_dev_id = Routed_Device_Object_Index();
|
||||||
@@ -112,9 +160,11 @@ static void cov_address_remove_unused(void)
|
|||||||
found = false;
|
found = false;
|
||||||
for (dev_id = 0; dev_id < Get_Num_Managed_Devices(); dev_id++) {
|
for (dev_id = 0; dev_id < Get_Num_Managed_Devices(); dev_id++) {
|
||||||
Set_Routed_Device_Object_Index(dev_id);
|
Set_Routed_Device_Object_Index(dev_id);
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
for (index = 0; index < Keylist_Count(COV_Subscriptions);
|
||||||
if ((COV_Subscriptions[index].flag.valid) &&
|
index++) {
|
||||||
(COV_Subscriptions[index].dest_index == cov_index)) {
|
subscription = Keylist_Data_Index(COV_Subscriptions, index);
|
||||||
|
if (subscription &&
|
||||||
|
(subscription->dest_index == cov_index)) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -133,9 +183,9 @@ static void cov_address_remove_unused(void)
|
|||||||
for (cov_index = 0; cov_index < MAX_COV_ADDRESSES; cov_index++) {
|
for (cov_index = 0; cov_index < MAX_COV_ADDRESSES; cov_index++) {
|
||||||
if (COV_Addresses[cov_index].valid) {
|
if (COV_Addresses[cov_index].valid) {
|
||||||
found = false;
|
found = false;
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
for (index = 0; index < Keylist_Count(COV_Subscriptions); index++) {
|
||||||
if ((COV_Subscriptions[index].flag.valid) &&
|
subscription = Keylist_Data_Index(COV_Subscriptions, index);
|
||||||
(COV_Subscriptions[index].dest_index == cov_index)) {
|
if (subscription && (subscription->dest_index == cov_index)) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -323,14 +373,15 @@ int handler_cov_encode_subscriptions(uint8_t *apdu, int max_apdu)
|
|||||||
};
|
};
|
||||||
unsigned index = 0;
|
unsigned index = 0;
|
||||||
int apdu_len = 0;
|
int apdu_len = 0;
|
||||||
|
BACNET_COV_SUBSCRIPTION *subscription = NULL;
|
||||||
|
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
for (index = 0; index < Keylist_Count(COV_Subscriptions); index++) {
|
||||||
if (COV_Subscriptions[index].flag.valid) {
|
subscription = Keylist_Data_Index(COV_Subscriptions, index);
|
||||||
|
if (subscription) {
|
||||||
/* Lets encode a COV subscription into an intermediate buffer
|
/* Lets encode a COV subscription into an intermediate buffer
|
||||||
* that can hold it */
|
* that can hold it */
|
||||||
int len = cov_encode_subscription(
|
int len = cov_encode_subscription(
|
||||||
&cov_sub[0], max_apdu - apdu_len,
|
&cov_sub[0], max_apdu - apdu_len, subscription);
|
||||||
&COV_Subscriptions[index]);
|
|
||||||
|
|
||||||
if ((apdu_len + len) > max_apdu) {
|
if ((apdu_len + len) > max_apdu) {
|
||||||
return -2;
|
return -2;
|
||||||
@@ -359,34 +410,18 @@ void handler_cov_init(void)
|
|||||||
uint16_t dev_id = 0;
|
uint16_t dev_id = 0;
|
||||||
for (dev_id = 0; dev_id < MAX_NUM_DEVICES; dev_id++) {
|
for (dev_id = 0; dev_id < MAX_NUM_DEVICES; dev_id++) {
|
||||||
Set_Routed_Device_Object_Index(dev_id);
|
Set_Routed_Device_Object_Index(dev_id);
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
if (!COV_Subscriptions) {
|
||||||
/* initialize with invalid COV address */
|
COV_Subscriptions = Keylist_Create();
|
||||||
COV_Subscriptions[index].flag.valid = false;
|
} else {
|
||||||
COV_Subscriptions[index].dest_index = MAX_COV_ADDRESSES;
|
Keylist_Data_Free(COV_Subscriptions);
|
||||||
COV_Subscriptions[index].subscriberProcessIdentifier = 0;
|
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type =
|
|
||||||
OBJECT_ANALOG_INPUT;
|
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance = 0;
|
|
||||||
COV_Subscriptions[index].flag.issueConfirmedNotifications = false;
|
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
|
||||||
COV_Subscriptions[index].lifetime = 0;
|
|
||||||
COV_Subscriptions[index].flag.send_requested = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Set_Routed_Device_Object_Index(current_dev_id);
|
Set_Routed_Device_Object_Index(current_dev_id);
|
||||||
#else
|
#else
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
if (!COV_Subscriptions) {
|
||||||
/* initialize with invalid COV address */
|
COV_Subscriptions = Keylist_Create();
|
||||||
COV_Subscriptions[index].flag.valid = false;
|
} else {
|
||||||
COV_Subscriptions[index].dest_index = MAX_COV_ADDRESSES;
|
Keylist_Data_Free(COV_Subscriptions);
|
||||||
COV_Subscriptions[index].subscriberProcessIdentifier = 0;
|
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type =
|
|
||||||
OBJECT_ANALOG_INPUT;
|
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance = 0;
|
|
||||||
COV_Subscriptions[index].flag.issueConfirmedNotifications = false;
|
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
|
||||||
COV_Subscriptions[index].lifetime = 0;
|
|
||||||
COV_Subscriptions[index].flag.send_requested = false;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
for (index = 0; index < MAX_COV_ADDRESSES; index++) {
|
for (index = 0; index < MAX_COV_ADDRESSES; index++) {
|
||||||
@@ -402,57 +437,54 @@ static bool cov_list_subscribe(
|
|||||||
{
|
{
|
||||||
bool existing_entry = false;
|
bool existing_entry = false;
|
||||||
int index;
|
int index;
|
||||||
int first_invalid_index = -1;
|
|
||||||
bool found = true;
|
bool found = true;
|
||||||
bool address_match = false;
|
bool address_match = false;
|
||||||
const BACNET_ADDRESS *dest = NULL;
|
const BACNET_ADDRESS *dest = NULL;
|
||||||
|
BACNET_COV_SUBSCRIPTION *subscription = NULL;
|
||||||
|
|
||||||
/* unable to subscribe - resources? */
|
/* unable to subscribe - resources? */
|
||||||
/* unable to cancel subscription - other? */
|
/* unable to cancel subscription - other? */
|
||||||
|
|
||||||
/* existing? - match Object ID and Process ID and address */
|
/* existing? - match Object ID and Process ID and address */
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
for (index = 0; index < Keylist_Count(COV_Subscriptions); index++) {
|
||||||
if (COV_Subscriptions[index].flag.valid) {
|
subscription = Keylist_Data_Index(COV_Subscriptions, index);
|
||||||
dest = cov_address_get(COV_Subscriptions[index].dest_index);
|
if (subscription) {
|
||||||
|
dest = cov_address_get(subscription->dest_index);
|
||||||
if (dest) {
|
if (dest) {
|
||||||
address_match = bacnet_address_same(src, dest);
|
address_match = bacnet_address_same(src, dest);
|
||||||
} else {
|
} else {
|
||||||
/* skip address matching - we don't have an address */
|
/* skip address matching - we don't have an address */
|
||||||
address_match = true;
|
address_match = true;
|
||||||
}
|
}
|
||||||
if ((COV_Subscriptions[index].monitoredObjectIdentifier.type ==
|
if ((subscription->monitoredObjectIdentifier.type ==
|
||||||
cov_data->monitoredObjectIdentifier.type) &&
|
cov_data->monitoredObjectIdentifier.type) &&
|
||||||
(COV_Subscriptions[index].monitoredObjectIdentifier.instance ==
|
(subscription->monitoredObjectIdentifier.instance ==
|
||||||
cov_data->monitoredObjectIdentifier.instance) &&
|
cov_data->monitoredObjectIdentifier.instance) &&
|
||||||
(COV_Subscriptions[index].subscriberProcessIdentifier ==
|
(subscription->subscriberProcessIdentifier ==
|
||||||
cov_data->subscriberProcessIdentifier) &&
|
cov_data->subscriberProcessIdentifier) &&
|
||||||
address_match) {
|
address_match) {
|
||||||
existing_entry = true;
|
existing_entry = true;
|
||||||
|
if (subscription->invokeID) {
|
||||||
|
tsm_free_invoke_id(subscription->invokeID);
|
||||||
|
subscription->invokeID = 0;
|
||||||
|
}
|
||||||
if (cov_data->cancellationRequest) {
|
if (cov_data->cancellationRequest) {
|
||||||
/* initialize with invalid COV address */
|
cov_subscription_delete(index);
|
||||||
COV_Subscriptions[index].flag.valid = false;
|
|
||||||
COV_Subscriptions[index].dest_index = MAX_COV_ADDRESSES;
|
|
||||||
cov_address_remove_unused();
|
cov_address_remove_unused();
|
||||||
} else {
|
} else {
|
||||||
COV_Subscriptions[index].dest_index = cov_address_add(src);
|
subscription->dest_index = cov_address_add(src);
|
||||||
COV_Subscriptions[index].flag.issueConfirmedNotifications =
|
subscription->flag.issueConfirmedNotifications =
|
||||||
cov_data->issueConfirmedNotifications;
|
cov_data->issueConfirmedNotifications;
|
||||||
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
subscription->lifetime = cov_data->lifetime;
|
||||||
COV_Subscriptions[index].flag.send_requested = true;
|
subscription->flag.send_requested = true;
|
||||||
}
|
|
||||||
if (COV_Subscriptions[index].invokeID) {
|
|
||||||
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (first_invalid_index < 0) {
|
|
||||||
first_invalid_index = index;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!existing_entry && (first_invalid_index >= 0) &&
|
if (!existing_entry &&
|
||||||
|
(Keylist_Count(COV_Subscriptions) < MAX_COV_SUBSCRIPTIONS) &&
|
||||||
(!cov_data->cancellationRequest)) {
|
(!cov_data->cancellationRequest)) {
|
||||||
const int addr_add_ret = cov_address_add(src);
|
const int addr_add_ret = cov_address_add(src);
|
||||||
|
|
||||||
@@ -461,24 +493,30 @@ static bool cov_list_subscribe(
|
|||||||
*error_code = ERROR_CODE_NO_SPACE_TO_ADD_LIST_ELEMENT;
|
*error_code = ERROR_CODE_NO_SPACE_TO_ADD_LIST_ELEMENT;
|
||||||
found = false;
|
found = false;
|
||||||
} else {
|
} else {
|
||||||
index = first_invalid_index;
|
|
||||||
found = true;
|
found = true;
|
||||||
COV_Subscriptions[index].dest_index = addr_add_ret;
|
index = Keylist_Next_Empty_Key(COV_Subscriptions, 0);
|
||||||
COV_Subscriptions[index].flag.valid = true;
|
subscription = cov_subscription_create(index);
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type =
|
if (subscription) {
|
||||||
cov_data->monitoredObjectIdentifier.type;
|
subscription->dest_index = addr_add_ret;
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance =
|
subscription->monitoredObjectIdentifier.type =
|
||||||
cov_data->monitoredObjectIdentifier.instance;
|
cov_data->monitoredObjectIdentifier.type;
|
||||||
COV_Subscriptions[index].subscriberProcessIdentifier =
|
subscription->monitoredObjectIdentifier.instance =
|
||||||
cov_data->subscriberProcessIdentifier;
|
cov_data->monitoredObjectIdentifier.instance;
|
||||||
COV_Subscriptions[index].flag.issueConfirmedNotifications =
|
subscription->subscriberProcessIdentifier =
|
||||||
cov_data->issueConfirmedNotifications;
|
cov_data->subscriberProcessIdentifier;
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
subscription->flag.issueConfirmedNotifications =
|
||||||
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
cov_data->issueConfirmedNotifications;
|
||||||
COV_Subscriptions[index].flag.send_requested = true;
|
subscription->invokeID = 0;
|
||||||
|
subscription->lifetime = cov_data->lifetime;
|
||||||
|
subscription->flag.send_requested = true;
|
||||||
|
} else {
|
||||||
|
*error_class = ERROR_CLASS_RESOURCES;
|
||||||
|
*error_code = ERROR_CODE_NO_SPACE_TO_ADD_LIST_ELEMENT;
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (!existing_entry) {
|
} else if (!existing_entry) {
|
||||||
if (first_invalid_index < 0) {
|
if (Keylist_Count(COV_Subscriptions) >= MAX_COV_SUBSCRIPTIONS) {
|
||||||
/* Out of resources */
|
/* Out of resources */
|
||||||
*error_class = ERROR_CLASS_RESOURCES;
|
*error_class = ERROR_CLASS_RESOURCES;
|
||||||
*error_code = ERROR_CODE_NO_SPACE_TO_ADD_LIST_ELEMENT;
|
*error_code = ERROR_CODE_NO_SPACE_TO_ADD_LIST_ELEMENT;
|
||||||
@@ -581,38 +619,38 @@ COV_FAILED:
|
|||||||
static void cov_lifetime_expiration_handler(
|
static void cov_lifetime_expiration_handler(
|
||||||
unsigned index, uint32_t elapsed_seconds, uint32_t lifetime_seconds)
|
unsigned index, uint32_t elapsed_seconds, uint32_t lifetime_seconds)
|
||||||
{
|
{
|
||||||
if (index < MAX_COV_SUBCRIPTIONS) {
|
if (index < MAX_COV_SUBSCRIPTIONS) {
|
||||||
|
BACNET_COV_SUBSCRIPTION *subscription =
|
||||||
|
Keylist_Data_Index(COV_Subscriptions, index);
|
||||||
/* handle lifetime expiration */
|
/* handle lifetime expiration */
|
||||||
if (lifetime_seconds >= elapsed_seconds) {
|
if (lifetime_seconds >= elapsed_seconds) {
|
||||||
COV_Subscriptions[index].lifetime -= elapsed_seconds;
|
subscription->lifetime -= elapsed_seconds;
|
||||||
#if 0
|
#if 0
|
||||||
fprintf(stderr, "COVtimer: subscription[%d].lifetime=%lu\n", index,
|
fprintf(stderr, "COVtimer: subscription[%d].lifetime=%lu\n", index,
|
||||||
(unsigned long) COV_Subscriptions[index].lifetime);
|
(unsigned long) subscription->lifetime);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
COV_Subscriptions[index].lifetime = 0;
|
subscription->lifetime = 0;
|
||||||
}
|
}
|
||||||
if (COV_Subscriptions[index].lifetime == 0) {
|
if (subscription->lifetime == 0) {
|
||||||
/* expire the subscription */
|
/* expire the subscription */
|
||||||
#if PRINT_ENABLED
|
#if PRINT_ENABLED
|
||||||
debug_fprintf(
|
debug_fprintf(
|
||||||
stderr, "COVtimer: PID=%u %s %u time remaining=%u seconds\n",
|
stderr, "COVtimer: PID=%u %s %u time remaining=%u seconds\n",
|
||||||
COV_Subscriptions[index].subscriberProcessIdentifier,
|
subscription->subscriberProcessIdentifier,
|
||||||
bactext_object_type_name(
|
bactext_object_type_name(
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type),
|
subscription->monitoredObjectIdentifier.type),
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance,
|
subscription->monitoredObjectIdentifier.instance,
|
||||||
COV_Subscriptions[index].lifetime);
|
subscription->lifetime);
|
||||||
#endif
|
#endif
|
||||||
/* initialize with invalid COV address */
|
if (subscription->flag.issueConfirmedNotifications) {
|
||||||
COV_Subscriptions[index].flag.valid = false;
|
if (subscription->invokeID) {
|
||||||
COV_Subscriptions[index].dest_index = MAX_COV_ADDRESSES;
|
tsm_free_invoke_id(subscription->invokeID);
|
||||||
cov_address_remove_unused();
|
subscription->invokeID = 0;
|
||||||
if (COV_Subscriptions[index].flag.issueConfirmedNotifications) {
|
|
||||||
if (COV_Subscriptions[index].invokeID) {
|
|
||||||
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cov_subscription_delete(index);
|
||||||
|
cov_address_remove_unused();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -640,18 +678,24 @@ static void cov_lifetime_expiration_handler(
|
|||||||
*/
|
*/
|
||||||
void handler_cov_timer_seconds(uint32_t elapsed_seconds)
|
void handler_cov_timer_seconds(uint32_t elapsed_seconds)
|
||||||
{
|
{
|
||||||
unsigned index = 0;
|
int index = 0;
|
||||||
uint32_t lifetime_seconds = 0;
|
uint32_t lifetime_seconds = 0;
|
||||||
|
BACNET_COV_SUBSCRIPTION *subscription = NULL;
|
||||||
|
int list_cnt = 0;
|
||||||
#ifdef BAC_ROUTING
|
#ifdef BAC_ROUTING
|
||||||
uint16_t current_dev_id = Routed_Device_Object_Index();
|
uint16_t current_dev_id = Routed_Device_Object_Index();
|
||||||
uint16_t dev_id = 0;
|
uint16_t dev_id = 0;
|
||||||
|
|
||||||
if (elapsed_seconds) {
|
if (elapsed_seconds) {
|
||||||
/* handle the subscription timeouts */
|
/* handle the subscription timeouts */
|
||||||
for (dev_id = 0; dev_id < Get_Num_Managed_Devices(); dev_id++) {
|
for (dev_id = 0; dev_id < Get_Num_Managed_Devices(); dev_id++) {
|
||||||
Set_Routed_Device_Object_Index(dev_id);
|
Set_Routed_Device_Object_Index(dev_id);
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
list_cnt = Keylist_Count(COV_Subscriptions);
|
||||||
if (COV_Subscriptions[index].flag.valid) {
|
/* Iterate in reverse order due to subscription deletion */
|
||||||
lifetime_seconds = COV_Subscriptions[index].lifetime;
|
for (index = list_cnt - 1; index >= 0; index--) {
|
||||||
|
subscription = Keylist_Data_Index(COV_Subscriptions, index);
|
||||||
|
if (subscription) {
|
||||||
|
lifetime_seconds = subscription->lifetime;
|
||||||
if (lifetime_seconds) {
|
if (lifetime_seconds) {
|
||||||
/* only expire COV with definite lifetimes */
|
/* only expire COV with definite lifetimes */
|
||||||
cov_lifetime_expiration_handler(
|
cov_lifetime_expiration_handler(
|
||||||
@@ -665,9 +709,12 @@ void handler_cov_timer_seconds(uint32_t elapsed_seconds)
|
|||||||
#else
|
#else
|
||||||
if (elapsed_seconds) {
|
if (elapsed_seconds) {
|
||||||
/* handle the subscription timeouts */
|
/* handle the subscription timeouts */
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
list_cnt = Keylist_Count(COV_Subscriptions);
|
||||||
if (COV_Subscriptions[index].flag.valid) {
|
/* Iterate in reverse order due to subscription deletion */
|
||||||
lifetime_seconds = COV_Subscriptions[index].lifetime;
|
for (index = list_cnt - 1; index >= 0; index--) {
|
||||||
|
subscription = Keylist_Data_Index(COV_Subscriptions, index);
|
||||||
|
if (subscription) {
|
||||||
|
lifetime_seconds = subscription->lifetime;
|
||||||
if (lifetime_seconds) {
|
if (lifetime_seconds) {
|
||||||
/* only expire COV with definite lifetimes */
|
/* only expire COV with definite lifetimes */
|
||||||
cov_lifetime_expiration_handler(
|
cov_lifetime_expiration_handler(
|
||||||
@@ -708,81 +755,81 @@ bool handler_cov_fsm(void)
|
|||||||
|
|
||||||
int index = indices[dev_id];
|
int index = indices[dev_id];
|
||||||
cov_fsm_state_t cov_task_state = cov_task_states[dev_id];
|
cov_fsm_state_t cov_task_state = cov_task_states[dev_id];
|
||||||
|
BACNET_COV_SUBSCRIPTION *subscription =
|
||||||
|
Keylist_Data_Index(COV_Subscriptions, index);
|
||||||
|
int list_cnt = Keylist_Count(COV_Subscriptions);
|
||||||
|
|
||||||
switch (cov_task_state) {
|
switch (cov_task_state) {
|
||||||
case COV_STATE_IDLE:
|
case COV_STATE_IDLE:
|
||||||
if (COV_Subscriptions[index].flag.valid) {
|
if (subscription) {
|
||||||
cov_task_state = COV_STATE_MARK;
|
cov_task_state = COV_STATE_MARK;
|
||||||
} else {
|
} else {
|
||||||
index++;
|
index++;
|
||||||
if (index >= MAX_COV_SUBCRIPTIONS) {
|
if (index >= list_cnt) {
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COV_STATE_MARK:
|
case COV_STATE_MARK:
|
||||||
/* mark any subscriptions where the value has changed */
|
/* mark any subscriptions where the value has changed */
|
||||||
if (COV_Subscriptions[index].flag.valid) {
|
if (subscription) {
|
||||||
object_type = (BACNET_OBJECT_TYPE)COV_Subscriptions[index]
|
object_type = (BACNET_OBJECT_TYPE)
|
||||||
.monitoredObjectIdentifier.type;
|
subscription->monitoredObjectIdentifier.type;
|
||||||
object_instance =
|
object_instance =
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
subscription->monitoredObjectIdentifier.instance;
|
||||||
status = Device_COV(object_type, object_instance);
|
status = Device_COV(object_type, object_instance);
|
||||||
if (status) {
|
if (status) {
|
||||||
COV_Subscriptions[index].flag.send_requested = true;
|
subscription->flag.send_requested = true;
|
||||||
#if PRINT_ENABLED
|
#if PRINT_ENABLED
|
||||||
debug_fprintf(stderr, "COVtask: Marking...\n");
|
debug_fprintf(stderr, "COVtask: Marking...\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
if (index >= MAX_COV_SUBCRIPTIONS) {
|
if (index >= list_cnt) {
|
||||||
index = 0;
|
index = 0;
|
||||||
cov_task_state = COV_STATE_CLEAR;
|
cov_task_state = COV_STATE_CLEAR;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COV_STATE_CLEAR:
|
case COV_STATE_CLEAR:
|
||||||
/* clear the COV flag after checking all subscriptions */
|
/* clear the COV flag after checking all subscriptions */
|
||||||
if ((COV_Subscriptions[index].flag.valid) &&
|
if (subscription && (subscription->flag.send_requested)) {
|
||||||
(COV_Subscriptions[index].flag.send_requested)) {
|
object_type = (BACNET_OBJECT_TYPE)
|
||||||
object_type = (BACNET_OBJECT_TYPE)COV_Subscriptions[index]
|
subscription->monitoredObjectIdentifier.type;
|
||||||
.monitoredObjectIdentifier.type;
|
|
||||||
object_instance =
|
object_instance =
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
subscription->monitoredObjectIdentifier.instance;
|
||||||
Device_COV_Clear(object_type, object_instance);
|
Device_COV_Clear(object_type, object_instance);
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
if (index >= MAX_COV_SUBCRIPTIONS) {
|
if (index >= list_cnt) {
|
||||||
index = 0;
|
index = 0;
|
||||||
cov_task_state = COV_STATE_FREE;
|
cov_task_state = COV_STATE_FREE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COV_STATE_FREE:
|
case COV_STATE_FREE:
|
||||||
/* confirmed notification house keeping */
|
/* confirmed notification house keeping */
|
||||||
if ((COV_Subscriptions[index].flag.valid) &&
|
if (subscription &&
|
||||||
(COV_Subscriptions[index].flag.issueConfirmedNotifications) &&
|
(subscription->flag.issueConfirmedNotifications) &&
|
||||||
(COV_Subscriptions[index].invokeID)) {
|
(subscription->invokeID)) {
|
||||||
if (tsm_invoke_id_free(COV_Subscriptions[index].invokeID)) {
|
if (tsm_invoke_id_free(subscription->invokeID)) {
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
subscription->invokeID = 0;
|
||||||
} else if (tsm_invoke_id_failed(
|
} else if (tsm_invoke_id_failed(subscription->invokeID)) {
|
||||||
COV_Subscriptions[index].invokeID)) {
|
tsm_free_invoke_id(subscription->invokeID);
|
||||||
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
subscription->invokeID = 0;
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
if (index >= MAX_COV_SUBCRIPTIONS) {
|
if (index >= list_cnt) {
|
||||||
index = 0;
|
index = 0;
|
||||||
cov_task_state = COV_STATE_SEND;
|
cov_task_state = COV_STATE_SEND;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COV_STATE_SEND:
|
case COV_STATE_SEND:
|
||||||
/* send any COVs that are requested */
|
/* send any COVs that are requested */
|
||||||
if ((COV_Subscriptions[index].flag.valid) &&
|
if (subscription && (subscription->flag.send_requested)) {
|
||||||
(COV_Subscriptions[index].flag.send_requested)) {
|
|
||||||
send = true;
|
send = true;
|
||||||
if (COV_Subscriptions[index].flag.issueConfirmedNotifications) {
|
if (subscription->flag.issueConfirmedNotifications) {
|
||||||
if (COV_Subscriptions[index].invokeID != 0) {
|
if (subscription->invokeID != 0) {
|
||||||
/* already sending */
|
/* already sending */
|
||||||
send = false;
|
send = false;
|
||||||
}
|
}
|
||||||
@@ -792,10 +839,11 @@ bool handler_cov_fsm(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (send) {
|
if (send) {
|
||||||
object_type = (BACNET_OBJECT_TYPE)COV_Subscriptions[index]
|
object_type =
|
||||||
.monitoredObjectIdentifier.type;
|
(BACNET_OBJECT_TYPE)
|
||||||
object_instance = COV_Subscriptions[index]
|
subscription->monitoredObjectIdentifier.type;
|
||||||
.monitoredObjectIdentifier.instance;
|
object_instance =
|
||||||
|
subscription->monitoredObjectIdentifier.instance;
|
||||||
#if PRINT_ENABLED
|
#if PRINT_ENABLED
|
||||||
debug_fprintf(stderr, "COVtask: Sending...\n");
|
debug_fprintf(stderr, "COVtask: Sending...\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -805,16 +853,15 @@ bool handler_cov_fsm(void)
|
|||||||
status = Device_Encode_Value_List(
|
status = Device_Encode_Value_List(
|
||||||
object_type, object_instance, &value_list[0]);
|
object_type, object_instance, &value_list[0]);
|
||||||
if (status) {
|
if (status) {
|
||||||
status = cov_send_request(
|
status = cov_send_request(subscription, &value_list[0]);
|
||||||
&COV_Subscriptions[index], &value_list[0]);
|
|
||||||
}
|
}
|
||||||
if (status) {
|
if (status) {
|
||||||
COV_Subscriptions[index].flag.send_requested = false;
|
subscription->flag.send_requested = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
if (index >= MAX_COV_SUBCRIPTIONS) {
|
if (index >= list_cnt) {
|
||||||
index = 0;
|
index = 0;
|
||||||
cov_task_state = COV_STATE_IDLE;
|
cov_task_state = COV_STATE_IDLE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ static bool CheckArraySize(OS_Keylist list)
|
|||||||
|
|
||||||
/* See if we got the memory we wanted */
|
/* See if we got the memory we wanted */
|
||||||
if (!new_array) {
|
if (!new_array) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy the nodes from the old array to the new array */
|
/* copy the nodes from the old array to the new array */
|
||||||
@@ -171,6 +171,11 @@ int Keylist_Data_Add(OS_Keylist list, KEY key, void *data)
|
|||||||
int i; /* counts through the array */
|
int i; /* counts through the array */
|
||||||
|
|
||||||
if (list && CheckArraySize(list)) {
|
if (list && CheckArraySize(list)) {
|
||||||
|
node = NodeCreate();
|
||||||
|
if (!node) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* figure out where to put the new node */
|
/* figure out where to put the new node */
|
||||||
if (list->count) {
|
if (list->count) {
|
||||||
(void)FindIndex(list, key, &index);
|
(void)FindIndex(list, key, &index);
|
||||||
@@ -190,14 +195,11 @@ int Keylist_Data_Add(OS_Keylist list, KEY key, void *data)
|
|||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create and add the node */
|
/* add the node */
|
||||||
node = NodeCreate();
|
list->count++;
|
||||||
if (node) {
|
node->key = key;
|
||||||
list->count++;
|
node->data = data;
|
||||||
node->key = key;
|
list->array[index] = node;
|
||||||
node->data = data;
|
|
||||||
list->array[index] = node;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user