From 26681f7f39887ed6e052cab1cd02e8f5f0c2432e Mon Sep 17 00:00:00 2001 From: skarg Date: Wed, 23 Nov 2011 18:52:53 +0000 Subject: [PATCH] Changed demo COV handler to reduce memory footprint, and to minimize the task cycle time. Also fixed COV clear race condition. --- bacnet-stack/demo/handler/h_cov.c | 221 ++++++++++++++++++------------ 1 file changed, 130 insertions(+), 91 deletions(-) diff --git a/bacnet-stack/demo/handler/h_cov.c b/bacnet-stack/demo/handler/h_cov.c index 17315ead..9df07a48 100644 --- a/bacnet-stack/demo/handler/h_cov.c +++ b/bacnet-stack/demo/handler/h_cov.c @@ -48,19 +48,23 @@ /* note: This COV service only monitors the properties 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 { - bool valid; + BACNET_COV_SUBSCRIPTION_FLAGS flag; BACNET_ADDRESS dest; uint32_t subscriberProcessIdentifier; BACNET_OBJECT_ID monitoredObjectIdentifier; - bool issueConfirmedNotifications; /* optional */ uint8_t invokeID; /* for confirmed COV */ uint32_t lifetime; /* optional */ - bool send_requested; } BACNET_COV_SUBSCRIPTION; #ifndef MAX_COV_SUBCRIPTIONS -#define MAX_COV_SUBCRIPTIONS 32 +#define MAX_COV_SUBCRIPTIONS 128 #endif static BACNET_COV_SUBSCRIPTION COV_Subscriptions[MAX_COV_SUBCRIPTIONS]; @@ -161,7 +165,7 @@ static int cov_encode_subscription( /* IssueConfirmedNotifications [2] BOOLEAN, */ len = encode_context_boolean(&apdu[apdu_len], 2, - cov_subscription->issueConfirmedNotifications); + cov_subscription->flag.issueConfirmedNotifications); apdu_len += len; /* TimeRemaining [3] Unsigned, */ len = @@ -193,7 +197,7 @@ int handler_cov_encode_subscriptions( if (apdu) { for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) { - if (COV_Subscriptions[index].valid) { + if (COV_Subscriptions[index].flag.valid) { len = cov_encode_subscription(&apdu[apdu_len], max_apdu - apdu_len, &COV_Subscriptions[index]); @@ -218,16 +222,16 @@ void handler_cov_init( unsigned index = 0; 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].subscriberProcessIdentifier = 0; COV_Subscriptions[index].monitoredObjectIdentifier.type = OBJECT_ANALOG_INPUT; 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].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 */ 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 == cov_data->monitoredObjectIdentifier.type) && (COV_Subscriptions[index].monitoredObjectIdentifier.instance == @@ -256,13 +260,13 @@ static bool cov_list_subscribe( cov_data->subscriberProcessIdentifier)) { existing_entry = true; if (cov_data->cancellationRequest) { - COV_Subscriptions[index].valid = false; + COV_Subscriptions[index].flag.valid = false; } else { bacnet_address_copy(&COV_Subscriptions[index].dest, src); - COV_Subscriptions[index].issueConfirmedNotifications = + COV_Subscriptions[index].flag.issueConfirmedNotifications = cov_data->issueConfirmedNotifications; 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) { tsm_free_invoke_id(COV_Subscriptions[index].invokeID); @@ -280,7 +284,7 @@ static bool cov_list_subscribe( (!cov_data->cancellationRequest)) { index = first_invalid_index; found = true; - COV_Subscriptions[index].valid = true; + COV_Subscriptions[index].flag.valid = true; bacnet_address_copy(&COV_Subscriptions[index].dest, src); COV_Subscriptions[index].monitoredObjectIdentifier.type = cov_data->monitoredObjectIdentifier.type; @@ -288,11 +292,11 @@ static bool cov_list_subscribe( cov_data->monitoredObjectIdentifier.instance; COV_Subscriptions[index].subscriberProcessIdentifier = cov_data->subscriberProcessIdentifier; - COV_Subscriptions[index].issueConfirmedNotifications = + COV_Subscriptions[index].flag.issueConfirmedNotifications = cov_data->issueConfirmedNotifications; COV_Subscriptions[index].invokeID = 0; COV_Subscriptions[index].lifetime = cov_data->lifetime; - COV_Subscriptions[index].send_requested = true; + COV_Subscriptions[index].flag.send_requested = true; } else if (!existing_entry) { if (first_invalid_index < 0) { /* Out of resources */ @@ -343,7 +347,7 @@ static bool cov_send_request( cov_subscription->monitoredObjectIdentifier.instance; cov_data.timeRemaining = cov_subscription->lifetime; cov_data.listOfValues = value_list; - if (cov_subscription->issueConfirmedNotifications) { + if (cov_subscription->flag.issueConfirmedNotifications) { invoke_id = tsm_next_free_invokeID(); if (invoke_id) { cov_subscription->invokeID = invoke_id; @@ -359,7 +363,7 @@ static bool cov_send_request( &cov_data); } pdu_len += len; - if (cov_subscription->issueConfirmedNotifications) { + if (cov_subscription->flag.issueConfirmedNotifications) { tsm_set_confirmed_unsegmented_transaction(invoke_id, &cov_subscription->dest, &npdu_data, &Handler_Transmit_Buffer[0], (uint16_t) pdu_len); @@ -405,7 +409,7 @@ void handler_cov_timer_seconds( /* handle the subscription timeouts */ for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) { - if (COV_Subscriptions[index].valid) { + if (COV_Subscriptions[index].flag.valid) { /* handle timeouts */ lifetime_seconds = COV_Subscriptions[index].lifetime; if (lifetime_seconds >= elapsed_seconds) { @@ -418,8 +422,8 @@ void handler_cov_timer_seconds( COV_Subscriptions[index].lifetime = 0; } if (COV_Subscriptions[index].lifetime == 0) { - COV_Subscriptions[index].valid = false; - if (COV_Subscriptions[index].issueConfirmedNotifications) { + COV_Subscriptions[index].flag.valid = false; + if (COV_Subscriptions[index].flag.issueConfirmedNotifications) { if (COV_Subscriptions[index].invokeID) { tsm_free_invoke_id(COV_Subscriptions[index].invokeID); COV_Subscriptions[index].invokeID = 0; @@ -432,88 +436,123 @@ void handler_cov_timer_seconds( void handler_cov_task(void) { - int index = 0; + static int index = 0; BACNET_OBJECT_TYPE object_type = MAX_BACNET_OBJECT_TYPE; uint32_t object_instance = 0; bool status = false; + bool send = false; 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 */ - value_list[0].next = &value_list[1]; - value_list[1].next = NULL; - /* mark any subscriptions where the value has changed */ - 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) { - 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; - } - } + switch (cov_task_state) { + case COV_STATE_IDLE: + index = 0; + cov_task_state = COV_STATE_MARK; + break; + case COV_STATE_MARK: + /* mark any subscriptions where the value has changed */ + if (COV_Subscriptions[index].flag.valid) { object_type = (BACNET_OBJECT_TYPE) COV_Subscriptions[index].monitoredObjectIdentifier.type; object_instance = COV_Subscriptions[index].monitoredObjectIdentifier.instance; - (void)Device_Encode_Value_List(object_type, object_instance, - &value_list[0]); - status = cov_send_request( - &COV_Subscriptions[index], - &value_list[0]); + status = Device_COV(object_type, object_instance); if (status) { - COV_Subscriptions[index].send_requested = false; - } else { - /* must be out of PDU space - stop for now */ - break; + COV_Subscriptions[index].flag.send_requested = true; } } - } + 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; } }