Changed demo COV handler to reduce memory footprint, and to minimize the task cycle time. Also fixed COV clear race condition.
This commit is contained in:
@@ -48,19 +48,23 @@
|
|||||||
|
|
||||||
/* 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 {
|
||||||
|
bool valid:1;
|
||||||
|
bool issueConfirmedNotifications:1; /* optional */
|
||||||
|
bool send_requested:1;
|
||||||
|
} BACNET_COV_SUBSCRIPTION_FLAGS;
|
||||||
|
|
||||||
typedef struct BACnet_COV_Subscription {
|
typedef struct BACnet_COV_Subscription {
|
||||||
bool valid;
|
BACNET_COV_SUBSCRIPTION_FLAGS flag;
|
||||||
BACNET_ADDRESS dest;
|
BACNET_ADDRESS dest;
|
||||||
uint32_t subscriberProcessIdentifier;
|
uint32_t subscriberProcessIdentifier;
|
||||||
BACNET_OBJECT_ID monitoredObjectIdentifier;
|
BACNET_OBJECT_ID monitoredObjectIdentifier;
|
||||||
bool issueConfirmedNotifications; /* optional */
|
|
||||||
uint8_t invokeID; /* for confirmed COV */
|
uint8_t invokeID; /* for confirmed COV */
|
||||||
uint32_t lifetime; /* optional */
|
uint32_t lifetime; /* optional */
|
||||||
bool send_requested;
|
|
||||||
} BACNET_COV_SUBSCRIPTION;
|
} BACNET_COV_SUBSCRIPTION;
|
||||||
|
|
||||||
#ifndef MAX_COV_SUBCRIPTIONS
|
#ifndef MAX_COV_SUBCRIPTIONS
|
||||||
#define MAX_COV_SUBCRIPTIONS 32
|
#define MAX_COV_SUBCRIPTIONS 128
|
||||||
#endif
|
#endif
|
||||||
static BACNET_COV_SUBSCRIPTION COV_Subscriptions[MAX_COV_SUBCRIPTIONS];
|
static BACNET_COV_SUBSCRIPTION COV_Subscriptions[MAX_COV_SUBCRIPTIONS];
|
||||||
|
|
||||||
@@ -161,7 +165,7 @@ static int cov_encode_subscription(
|
|||||||
/* IssueConfirmedNotifications [2] BOOLEAN, */
|
/* IssueConfirmedNotifications [2] BOOLEAN, */
|
||||||
len =
|
len =
|
||||||
encode_context_boolean(&apdu[apdu_len], 2,
|
encode_context_boolean(&apdu[apdu_len], 2,
|
||||||
cov_subscription->issueConfirmedNotifications);
|
cov_subscription->flag.issueConfirmedNotifications);
|
||||||
apdu_len += len;
|
apdu_len += len;
|
||||||
/* TimeRemaining [3] Unsigned, */
|
/* TimeRemaining [3] Unsigned, */
|
||||||
len =
|
len =
|
||||||
@@ -193,7 +197,7 @@ int handler_cov_encode_subscriptions(
|
|||||||
|
|
||||||
if (apdu) {
|
if (apdu) {
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
||||||
if (COV_Subscriptions[index].valid) {
|
if (COV_Subscriptions[index].flag.valid) {
|
||||||
len =
|
len =
|
||||||
cov_encode_subscription(&apdu[apdu_len],
|
cov_encode_subscription(&apdu[apdu_len],
|
||||||
max_apdu - apdu_len, &COV_Subscriptions[index]);
|
max_apdu - apdu_len, &COV_Subscriptions[index]);
|
||||||
@@ -218,16 +222,16 @@ void handler_cov_init(
|
|||||||
unsigned index = 0;
|
unsigned index = 0;
|
||||||
|
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
||||||
COV_Subscriptions[index].valid = false;
|
COV_Subscriptions[index].flag.valid = false;
|
||||||
COV_Subscriptions[index].dest.mac_len = 0;
|
COV_Subscriptions[index].dest.mac_len = 0;
|
||||||
COV_Subscriptions[index].subscriberProcessIdentifier = 0;
|
COV_Subscriptions[index].subscriberProcessIdentifier = 0;
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type =
|
COV_Subscriptions[index].monitoredObjectIdentifier.type =
|
||||||
OBJECT_ANALOG_INPUT;
|
OBJECT_ANALOG_INPUT;
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance = 0;
|
COV_Subscriptions[index].monitoredObjectIdentifier.instance = 0;
|
||||||
COV_Subscriptions[index].issueConfirmedNotifications = false;
|
COV_Subscriptions[index].flag.issueConfirmedNotifications = false;
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
COV_Subscriptions[index].lifetime = 0;
|
COV_Subscriptions[index].lifetime = 0;
|
||||||
COV_Subscriptions[index].send_requested = false;
|
COV_Subscriptions[index].flag.send_requested = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +251,7 @@ static bool cov_list_subscribe(
|
|||||||
|
|
||||||
/* existing? - match Object ID and Process ID */
|
/* existing? - match Object ID and Process ID */
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
||||||
if (COV_Subscriptions[index].valid) {
|
if (COV_Subscriptions[index].flag.valid) {
|
||||||
if ((COV_Subscriptions[index].monitoredObjectIdentifier.type ==
|
if ((COV_Subscriptions[index].monitoredObjectIdentifier.type ==
|
||||||
cov_data->monitoredObjectIdentifier.type) &&
|
cov_data->monitoredObjectIdentifier.type) &&
|
||||||
(COV_Subscriptions[index].monitoredObjectIdentifier.instance ==
|
(COV_Subscriptions[index].monitoredObjectIdentifier.instance ==
|
||||||
@@ -256,13 +260,13 @@ static bool cov_list_subscribe(
|
|||||||
cov_data->subscriberProcessIdentifier)) {
|
cov_data->subscriberProcessIdentifier)) {
|
||||||
existing_entry = true;
|
existing_entry = true;
|
||||||
if (cov_data->cancellationRequest) {
|
if (cov_data->cancellationRequest) {
|
||||||
COV_Subscriptions[index].valid = false;
|
COV_Subscriptions[index].flag.valid = false;
|
||||||
} else {
|
} else {
|
||||||
bacnet_address_copy(&COV_Subscriptions[index].dest, src);
|
bacnet_address_copy(&COV_Subscriptions[index].dest, src);
|
||||||
COV_Subscriptions[index].issueConfirmedNotifications =
|
COV_Subscriptions[index].flag.issueConfirmedNotifications =
|
||||||
cov_data->issueConfirmedNotifications;
|
cov_data->issueConfirmedNotifications;
|
||||||
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
||||||
COV_Subscriptions[index].send_requested = true;
|
COV_Subscriptions[index].flag.send_requested = true;
|
||||||
}
|
}
|
||||||
if (COV_Subscriptions[index].invokeID) {
|
if (COV_Subscriptions[index].invokeID) {
|
||||||
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
||||||
@@ -280,7 +284,7 @@ static bool cov_list_subscribe(
|
|||||||
(!cov_data->cancellationRequest)) {
|
(!cov_data->cancellationRequest)) {
|
||||||
index = first_invalid_index;
|
index = first_invalid_index;
|
||||||
found = true;
|
found = true;
|
||||||
COV_Subscriptions[index].valid = true;
|
COV_Subscriptions[index].flag.valid = true;
|
||||||
bacnet_address_copy(&COV_Subscriptions[index].dest, src);
|
bacnet_address_copy(&COV_Subscriptions[index].dest, src);
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type =
|
COV_Subscriptions[index].monitoredObjectIdentifier.type =
|
||||||
cov_data->monitoredObjectIdentifier.type;
|
cov_data->monitoredObjectIdentifier.type;
|
||||||
@@ -288,11 +292,11 @@ static bool cov_list_subscribe(
|
|||||||
cov_data->monitoredObjectIdentifier.instance;
|
cov_data->monitoredObjectIdentifier.instance;
|
||||||
COV_Subscriptions[index].subscriberProcessIdentifier =
|
COV_Subscriptions[index].subscriberProcessIdentifier =
|
||||||
cov_data->subscriberProcessIdentifier;
|
cov_data->subscriberProcessIdentifier;
|
||||||
COV_Subscriptions[index].issueConfirmedNotifications =
|
COV_Subscriptions[index].flag.issueConfirmedNotifications =
|
||||||
cov_data->issueConfirmedNotifications;
|
cov_data->issueConfirmedNotifications;
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
||||||
COV_Subscriptions[index].send_requested = true;
|
COV_Subscriptions[index].flag.send_requested = true;
|
||||||
} else if (!existing_entry) {
|
} else if (!existing_entry) {
|
||||||
if (first_invalid_index < 0) {
|
if (first_invalid_index < 0) {
|
||||||
/* Out of resources */
|
/* Out of resources */
|
||||||
@@ -343,7 +347,7 @@ static bool cov_send_request(
|
|||||||
cov_subscription->monitoredObjectIdentifier.instance;
|
cov_subscription->monitoredObjectIdentifier.instance;
|
||||||
cov_data.timeRemaining = cov_subscription->lifetime;
|
cov_data.timeRemaining = cov_subscription->lifetime;
|
||||||
cov_data.listOfValues = value_list;
|
cov_data.listOfValues = value_list;
|
||||||
if (cov_subscription->issueConfirmedNotifications) {
|
if (cov_subscription->flag.issueConfirmedNotifications) {
|
||||||
invoke_id = tsm_next_free_invokeID();
|
invoke_id = tsm_next_free_invokeID();
|
||||||
if (invoke_id) {
|
if (invoke_id) {
|
||||||
cov_subscription->invokeID = invoke_id;
|
cov_subscription->invokeID = invoke_id;
|
||||||
@@ -359,7 +363,7 @@ static bool cov_send_request(
|
|||||||
&cov_data);
|
&cov_data);
|
||||||
}
|
}
|
||||||
pdu_len += len;
|
pdu_len += len;
|
||||||
if (cov_subscription->issueConfirmedNotifications) {
|
if (cov_subscription->flag.issueConfirmedNotifications) {
|
||||||
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
tsm_set_confirmed_unsegmented_transaction(invoke_id,
|
||||||
&cov_subscription->dest, &npdu_data, &Handler_Transmit_Buffer[0],
|
&cov_subscription->dest, &npdu_data, &Handler_Transmit_Buffer[0],
|
||||||
(uint16_t) pdu_len);
|
(uint16_t) pdu_len);
|
||||||
@@ -405,7 +409,7 @@ void handler_cov_timer_seconds(
|
|||||||
|
|
||||||
/* handle the subscription timeouts */
|
/* handle the subscription timeouts */
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
||||||
if (COV_Subscriptions[index].valid) {
|
if (COV_Subscriptions[index].flag.valid) {
|
||||||
/* handle timeouts */
|
/* handle timeouts */
|
||||||
lifetime_seconds = COV_Subscriptions[index].lifetime;
|
lifetime_seconds = COV_Subscriptions[index].lifetime;
|
||||||
if (lifetime_seconds >= elapsed_seconds) {
|
if (lifetime_seconds >= elapsed_seconds) {
|
||||||
@@ -418,8 +422,8 @@ void handler_cov_timer_seconds(
|
|||||||
COV_Subscriptions[index].lifetime = 0;
|
COV_Subscriptions[index].lifetime = 0;
|
||||||
}
|
}
|
||||||
if (COV_Subscriptions[index].lifetime == 0) {
|
if (COV_Subscriptions[index].lifetime == 0) {
|
||||||
COV_Subscriptions[index].valid = false;
|
COV_Subscriptions[index].flag.valid = false;
|
||||||
if (COV_Subscriptions[index].issueConfirmedNotifications) {
|
if (COV_Subscriptions[index].flag.issueConfirmedNotifications) {
|
||||||
if (COV_Subscriptions[index].invokeID) {
|
if (COV_Subscriptions[index].invokeID) {
|
||||||
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
@@ -432,88 +436,123 @@ void handler_cov_timer_seconds(
|
|||||||
|
|
||||||
void handler_cov_task(void)
|
void handler_cov_task(void)
|
||||||
{
|
{
|
||||||
int index = 0;
|
static int index = 0;
|
||||||
BACNET_OBJECT_TYPE object_type = MAX_BACNET_OBJECT_TYPE;
|
BACNET_OBJECT_TYPE object_type = MAX_BACNET_OBJECT_TYPE;
|
||||||
uint32_t object_instance = 0;
|
uint32_t object_instance = 0;
|
||||||
bool status = false;
|
bool status = false;
|
||||||
|
bool send = false;
|
||||||
BACNET_PROPERTY_VALUE value_list[2];
|
BACNET_PROPERTY_VALUE value_list[2];
|
||||||
|
/* states for transmitting */
|
||||||
|
static enum
|
||||||
|
{
|
||||||
|
COV_STATE_IDLE = 0,
|
||||||
|
COV_STATE_MARK,
|
||||||
|
COV_STATE_CLEAR,
|
||||||
|
COV_STATE_FREE,
|
||||||
|
COV_STATE_SEND
|
||||||
|
} cov_task_state = COV_STATE_IDLE;
|
||||||
|
|
||||||
/* configure the linked list for the two properties */
|
switch (cov_task_state) {
|
||||||
value_list[0].next = &value_list[1];
|
case COV_STATE_IDLE:
|
||||||
value_list[1].next = NULL;
|
index = 0;
|
||||||
/* mark any subscriptions where the value has changed */
|
cov_task_state = COV_STATE_MARK;
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
break;
|
||||||
if (COV_Subscriptions[index].valid) {
|
case COV_STATE_MARK:
|
||||||
object_type = (BACNET_OBJECT_TYPE)
|
/* mark any subscriptions where the value has changed */
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
if (COV_Subscriptions[index].flag.valid) {
|
||||||
object_instance =
|
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
|
||||||
status = Device_COV(object_type, object_instance);
|
|
||||||
if (status) {
|
|
||||||
COV_Subscriptions[index].send_requested = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* clear the COV flag after checking all subscriptions (dup objects) */
|
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
|
||||||
if (COV_Subscriptions[index].valid) {
|
|
||||||
object_type = (BACNET_OBJECT_TYPE)
|
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
|
||||||
object_instance =
|
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
|
||||||
status = Device_COV(object_type, object_instance);
|
|
||||||
if (status) {
|
|
||||||
Device_COV_Clear(object_type, object_instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* confirmed notification house keeping */
|
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
|
||||||
if (COV_Subscriptions[index].valid) {
|
|
||||||
if (COV_Subscriptions[index].issueConfirmedNotifications) {
|
|
||||||
if (COV_Subscriptions[index].invokeID) {
|
|
||||||
if (tsm_invoke_id_free(COV_Subscriptions[index].invokeID)) {
|
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
|
||||||
} else if (tsm_invoke_id_failed(
|
|
||||||
COV_Subscriptions[index].invokeID)) {
|
|
||||||
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
|
||||||
COV_Subscriptions[index].invokeID = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* send any COVs that are requested */
|
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
|
||||||
if (COV_Subscriptions[index].valid) {
|
|
||||||
if (COV_Subscriptions[index].send_requested) {
|
|
||||||
if (COV_Subscriptions[index].issueConfirmedNotifications) {
|
|
||||||
if (COV_Subscriptions[index].invokeID != 0) {
|
|
||||||
/* already sending - be patient! */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!tsm_transaction_available()) {
|
|
||||||
/* no free transactions - be patient! */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
object_type = (BACNET_OBJECT_TYPE)
|
object_type = (BACNET_OBJECT_TYPE)
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
||||||
object_instance =
|
object_instance =
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
||||||
(void)Device_Encode_Value_List(object_type, object_instance,
|
status = Device_COV(object_type, object_instance);
|
||||||
&value_list[0]);
|
|
||||||
status = cov_send_request(
|
|
||||||
&COV_Subscriptions[index],
|
|
||||||
&value_list[0]);
|
|
||||||
if (status) {
|
if (status) {
|
||||||
COV_Subscriptions[index].send_requested = false;
|
COV_Subscriptions[index].flag.send_requested = true;
|
||||||
} else {
|
|
||||||
/* must be out of PDU space - stop for now */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
index++;
|
||||||
|
if (index >= MAX_COV_SUBCRIPTIONS) {
|
||||||
|
index = 0;
|
||||||
|
cov_task_state = COV_STATE_CLEAR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COV_STATE_CLEAR:
|
||||||
|
/* clear the COV flag after checking all subscriptions */
|
||||||
|
if ((COV_Subscriptions[index].flag.valid) &&
|
||||||
|
(COV_Subscriptions[index].flag.send_requested)) {
|
||||||
|
object_type = (BACNET_OBJECT_TYPE)
|
||||||
|
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
||||||
|
object_instance =
|
||||||
|
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
||||||
|
Device_COV_Clear(object_type, object_instance);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
if (index >= MAX_COV_SUBCRIPTIONS) {
|
||||||
|
index = 0;
|
||||||
|
cov_task_state = COV_STATE_FREE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COV_STATE_FREE:
|
||||||
|
/* confirmed notification house keeping */
|
||||||
|
if ((COV_Subscriptions[index].flag.valid) &&
|
||||||
|
(COV_Subscriptions[index].flag.issueConfirmedNotifications) &&
|
||||||
|
(COV_Subscriptions[index].invokeID)) {
|
||||||
|
if (tsm_invoke_id_free(COV_Subscriptions[index].invokeID)) {
|
||||||
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
|
} else if (tsm_invoke_id_failed(
|
||||||
|
COV_Subscriptions[index].invokeID)) {
|
||||||
|
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
||||||
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
if (index >= MAX_COV_SUBCRIPTIONS) {
|
||||||
|
index = 0;
|
||||||
|
cov_task_state = COV_STATE_SEND;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COV_STATE_SEND:
|
||||||
|
/* send any COVs that are requested */
|
||||||
|
if ((COV_Subscriptions[index].flag.valid) &&
|
||||||
|
(COV_Subscriptions[index].flag.send_requested)) {
|
||||||
|
send = true;
|
||||||
|
if (COV_Subscriptions[index].flag.issueConfirmedNotifications) {
|
||||||
|
if (COV_Subscriptions[index].invokeID != 0) {
|
||||||
|
/* already sending */
|
||||||
|
send = false;
|
||||||
|
}
|
||||||
|
if (!tsm_transaction_available()) {
|
||||||
|
/* no transactions available - can't send now */
|
||||||
|
send = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (send) {
|
||||||
|
object_type = (BACNET_OBJECT_TYPE)
|
||||||
|
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
||||||
|
object_instance =
|
||||||
|
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
||||||
|
/* configure the linked list for the two properties */
|
||||||
|
value_list[0].next = &value_list[1];
|
||||||
|
value_list[1].next = NULL;
|
||||||
|
(void)Device_Encode_Value_List(object_type, object_instance,
|
||||||
|
&value_list[0]);
|
||||||
|
status = cov_send_request(
|
||||||
|
&COV_Subscriptions[index],
|
||||||
|
&value_list[0]);
|
||||||
|
if (status) {
|
||||||
|
COV_Subscriptions[index].flag.send_requested = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
if (index >= MAX_COV_SUBCRIPTIONS) {
|
||||||
|
index = 0;
|
||||||
|
cov_task_state = COV_STATE_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
index = 0;
|
||||||
|
cov_task_state = COV_STATE_IDLE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user