/* gets the next free invokeID,
   and reserves a spot in the table
   returns 0 if none are available */
uint8_t tsm_next_free_invokeID(
    void)
{
    uint8_t index = 0;
    uint8_t invokeID = 0;
    bool found = false;

    /* is there even space available? */
    if (tsm_transaction_available()) {
        while (!found) {
            index = tsm_find_invokeID_index(Current_Invoke_ID);
            if (index == MAX_TSM_TRANSACTIONS) {
                /* Not found, so this invokeID is not used */
                found = true;
                /* set this id into the table */
                index = tsm_find_first_free_index();
                if (index != MAX_TSM_TRANSACTIONS) {
                    TSM_List[index].InvokeID = invokeID = Current_Invoke_ID;
                    TSM_List[index].state = TSM_STATE_IDLE;
                    TSM_List[index].RequestTimer = apdu_timeout();
                    /* update for the next call or check */
                    Current_Invoke_ID++;
                    /* skip zero - we treat that internally as invalid or no free */
                    if (Current_Invoke_ID == 0) {
                        Current_Invoke_ID = 1;
                    }
                }
            } else {
                /* found! This invokeID is already used */
                /* try next one */
                Current_Invoke_ID++;
                /* skip zero - we treat that internally as invalid or no free */
                if (Current_Invoke_ID == 0) {
                    Current_Invoke_ID = 1;
                }
            }
        }
    }

    return invokeID;
}
Exemple #2
0
void handler_cov_task(
    void)
{
    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;

    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;
                status = Device_COV(object_type, object_instance);
                if (status) {
                    COV_Subscriptions[index].flag.send_requested = true;
#if PRINT_ENABLED
                    fprintf(stderr, "COVtask: Marking...\n");
#endif
                }
            }
            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;
#if PRINT_ENABLED
                    fprintf(stderr, "COVtask: Sending...\n");
#endif
                    /* 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;
    }
}