From 8199008092fbcd5e37758f1331c484476317baea Mon Sep 17 00:00:00 2001 From: k001a Date: Thu, 21 Jul 2011 20:44:57 +0000 Subject: [PATCH] Acknowledge Alarm for Analog-Input and Analog-Value objects. Moved initialization of handlers to GetEventInformations to specific init object. --- bacnet-stack/demo/handler/h_alarm_ack.c | 84 +++++++++++++++---- bacnet-stack/demo/object/ai.c | 105 +++++++++++++++++++++++- bacnet-stack/demo/object/ai.h | 3 + bacnet-stack/demo/object/av.c | 105 +++++++++++++++++++++++- bacnet-stack/demo/object/av.h | 3 + bacnet-stack/demo/server/main.c | 11 +-- bacnet-stack/include/alarm_ack.h | 8 ++ bacnet-stack/include/handlers.h | 5 ++ bacnet-stack/lib/Makefile | 1 + 9 files changed, 297 insertions(+), 28 deletions(-) diff --git a/bacnet-stack/demo/handler/h_alarm_ack.c b/bacnet-stack/demo/handler/h_alarm_ack.c index 17846296..cf09825b 100644 --- a/bacnet-stack/demo/handler/h_alarm_ack.c +++ b/bacnet-stack/demo/handler/h_alarm_ack.c @@ -1,6 +1,7 @@ /************************************************************************** * * Copyright (C) 2005 Steve Karg +* Copyright (C) 2011 Krzysztof Malorny * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,10 +28,13 @@ #include #include #include + #include "config.h" #include "txbuf.h" #include "bacdef.h" #include "bacdcode.h" +#include "bacerror.h" +#include "bactext.h" #include "apdu.h" #include "npdu.h" #include "abort.h" @@ -39,6 +43,17 @@ /** @file h_alarm_ack.c Handles Alarm Acknowledgment. */ +static alarm_ack_function Alarm_Ack[MAX_BACNET_OBJECT_TYPE]; + +void handler_alarm_ack_set( + BACNET_OBJECT_TYPE object_type, + alarm_ack_function pFunction) +{ + if (object_type < MAX_BACNET_OBJECT_TYPE) { + Alarm_Ack[object_type] = pFunction; + } +} + /** Handler for an Alarm/Event Acknowledgement. * @ingroup ALMACK * This handler will be invoked by apdu_handler() if it has been enabled @@ -48,12 +63,12 @@ * - the message is segmented * - if decoding fails * - Otherwise, sends a simple ACK - * + * * @param service_request [in] The contents of the service request. * @param service_len [in] The length of the service_request. * @param src [in] BACNET_ADDRESS of the source of the message - * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information - * decoded from the APDU header of this message. + * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information + * decoded from the APDU header of this message. */ void handler_alarm_ack( uint8_t * service_request, @@ -61,12 +76,14 @@ void handler_alarm_ack( BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { - BACNET_ALARM_ACK_DATA data; int len = 0; int pdu_len = 0; - BACNET_NPDU_DATA npdu_data; int bytes_sent = 0; + int ack_result = 0; BACNET_ADDRESS my_address; + BACNET_NPDU_DATA npdu_data; + BACNET_ALARM_ACK_DATA data; + BACNET_ERROR_CODE error_code; /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); @@ -103,25 +120,60 @@ void handler_alarm_ack( goto AA_ABORT; } - /* - ** Process Life Safety Operation Here - */ #if PRINT_ENABLED fprintf(stderr, - "Alarm Ack Operation: Received acknowledge for object id %lu from %s for process id %lu for object %lu\n", + "Alarm Ack Operation: Received acknowledge for object id (%d, %lu) from %s for process id %lu \n", + data.eventObjectIdentifier.type, (unsigned long) data.eventObjectIdentifier.instance, - data.ackSource.value, (unsigned long) data.ackProcessIdentifier, - (unsigned long) data.eventObjectIdentifier.instance); + data.ackSource.value, (unsigned long) data.ackProcessIdentifier); #endif - len = - encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], - service_data->invoke_id, SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM); + + if (Alarm_Ack[data.eventObjectIdentifier.type]) { + + ack_result = Alarm_Ack[data.eventObjectIdentifier.type](&data, &error_code); + + switch (ack_result) + { + case 1: + len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM); #if PRINT_ENABLED - fprintf(stderr, "Alarm Acknowledge: " "Sending Simple Ack!\n"); + fprintf(stderr, "Alarm Acknowledge: " "Sending Simple Ack!\n"); #endif + break; - AA_ABORT: + case -1: + len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM, + ERROR_CLASS_OBJECT, error_code); +#if PRINT_ENABLED + fprintf(stderr, "Alarm Acknowledge: error %s!\n", + bactext_error_code_name(error_code)); +#endif + break; + + default: + len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, ABORT_REASON_OTHER, true); +#if PRINT_ENABLED + fprintf(stderr, "Alarm Acknowledge: abort other!\n"); +#endif + break; + } + } + else { + len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM, + ERROR_CLASS_OBJECT, ERROR_CODE_NO_ALARM_CONFIGURED); +#if PRINT_ENABLED + fprintf(stderr, "Alarm Acknowledge: error %s!\n", + bactext_error_code_name(ERROR_CODE_NO_ALARM_CONFIGURED)); +#endif + } + + +AA_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], diff --git a/bacnet-stack/demo/object/ai.c b/bacnet-stack/demo/object/ai.c index c4dc5e92..0e733922 100644 --- a/bacnet-stack/demo/object/ai.c +++ b/bacnet-stack/demo/object/ai.c @@ -122,6 +122,13 @@ void Analog_Input_Init( datetime_wildcard_set(&AI_Descr[i].Event_Time_Stamps[j]); AI_Descr[i].Acked_Transitions[j].bIsAcked = true; } + + /* Set handler for GetEventInformation function */ + handler_get_event_information_set(OBJECT_ANALOG_INPUT, + Analog_Input_Event_Information); + /* Set handler for AcknowledgeAlarm function */ + handler_alarm_ack_set(OBJECT_ANALOG_INPUT, + Analog_Input_Alarm_Ack); #endif } } @@ -873,10 +880,10 @@ void Analog_Input_Intrinsic_Reporting(uint32_t object_instance) } +#if defined(INTRINSIC_REPORTING) int Analog_Input_Event_Information(unsigned index, BACNET_GET_EVENT_INFORMATION_DATA * getevent_data) { -#if defined(INTRINSIC_REPORTING) bool IsNotAckedTransitions; bool IsActiveEvent; int i; @@ -934,10 +941,104 @@ int Analog_Input_Event_Information(unsigned index, } else return 0; /* no active event at this index */ -#endif /* defined(INTRINSIC_REPORTING) */ } +int Analog_Input_Alarm_Ack(BACNET_ALARM_ACK_DATA * alarmack_data, + BACNET_ERROR_CODE * error_code) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned int object_index; + + + object_index = Analog_Input_Instance_To_Index( + alarmack_data->eventObjectIdentifier.instance); + + if (object_index < MAX_ANALOG_INPUTS) + CurrentAI = &AI_Descr[object_index]; + else { + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + return -1; + } + + switch (alarmack_data->eventStateAcked) + { + case EVENT_STATE_OFFNORMAL: + case EVENT_STATE_HIGH_LIMIT: + case EVENT_STATE_LOW_LIMIT: + if(CurrentAI->Acked_Transitions[TRANSITION_TO_OFFNORMAL].bIsAcked == false) { + if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){ + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + if(datetime_compare(&CurrentAI->Acked_Transitions[TRANSITION_TO_OFFNORMAL].Time_Stamp, + &alarmack_data->eventTimeStamp.value.dateTime) > 0) + { + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + + /* FIXME: Send ack notification */ + CurrentAI->Acked_Transitions[TRANSITION_TO_OFFNORMAL].bIsAcked = true; + } + else { + *error_code = ERROR_CODE_INVALID_EVENT_STATE; + return -1; + } + break; + + case EVENT_STATE_FAULT: + if(CurrentAI->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked == false) { + if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){ + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + if(datetime_compare(&CurrentAI->Acked_Transitions[TRANSITION_TO_NORMAL].Time_Stamp, + &alarmack_data->eventTimeStamp.value.dateTime) > 0) + { + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + + /* FIXME: Send ack notification */ + CurrentAI->Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked = true; + } + else { + *error_code = ERROR_CODE_INVALID_EVENT_STATE; + return -1; + } + break; + + case EVENT_STATE_NORMAL: + if(CurrentAI->Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked == false) { + if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){ + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + if(datetime_compare(&CurrentAI->Acked_Transitions[TRANSITION_TO_FAULT].Time_Stamp, + &alarmack_data->eventTimeStamp.value.dateTime) > 0) + { + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + + /* FIXME: Send ack notification */ + CurrentAI->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked = true; + } + else { + *error_code = ERROR_CODE_INVALID_EVENT_STATE; + return -1; + } + break; + + default: + return -2; + } + + return 1; +} +#endif /* defined(INTRINSIC_REPORTING) */ + #ifdef TEST #include diff --git a/bacnet-stack/demo/object/ai.h b/bacnet-stack/demo/object/ai.h index fa7b7dab..cbbb2f0d 100644 --- a/bacnet-stack/demo/object/ai.h +++ b/bacnet-stack/demo/object/ai.h @@ -113,6 +113,9 @@ extern "C" { int Analog_Input_Event_Information(unsigned index, BACNET_GET_EVENT_INFORMATION_DATA * getevent_data); + int Analog_Input_Alarm_Ack(BACNET_ALARM_ACK_DATA * alarmack_data, + BACNET_ERROR_CODE * error_code); + void Analog_Input_Init( void); diff --git a/bacnet-stack/demo/object/av.c b/bacnet-stack/demo/object/av.c index dd80c445..77375144 100644 --- a/bacnet-stack/demo/object/av.c +++ b/bacnet-stack/demo/object/av.c @@ -37,6 +37,7 @@ #include "bacapp.h" #include "bactext.h" #include "config.h" /* the custom stuff */ +#include "alarm_ack.h" #include "getevent.h" #include "wp.h" #include "rp.h" @@ -131,6 +132,13 @@ void Analog_Value_Init( datetime_wildcard_set(&AV_Descr[i].Event_Time_Stamps[j]); AV_Descr[i].Acked_Transitions[j].bIsAcked = true; } + + /* Set handler for GetEventInformation function */ + handler_get_event_information_set(OBJECT_ANALOG_VALUE, + Analog_Value_Event_Information); + /* Set handler for AcknowledgeAlarm function */ + handler_alarm_ack_set(OBJECT_ANALOG_VALUE, + Analog_Value_Alarm_Ack); #endif } } @@ -983,10 +991,10 @@ void Analog_Value_Intrinsic_Reporting(uint32_t object_instance) } +#if defined(INTRINSIC_REPORTING) int Analog_Value_Event_Information(unsigned index, BACNET_GET_EVENT_INFORMATION_DATA * getevent_data) { -#if defined(INTRINSIC_REPORTING) bool IsNotAckedTransitions; bool IsActiveEvent; int i; @@ -1044,9 +1052,102 @@ int Analog_Value_Event_Information(unsigned index, } else return 0; /* no active event at this index */ -#endif /* defined(INTRINSIC_REPORTING) */ } +int Analog_Value_Alarm_Ack(BACNET_ALARM_ACK_DATA * alarmack_data, + BACNET_ERROR_CODE * error_code) +{ + ANALOG_VALUE_DESCR *CurrentAV; + unsigned int object_index; + + + object_index = Analog_Value_Instance_To_Index( + alarmack_data->eventObjectIdentifier.instance); + + if (object_index < MAX_ANALOG_VALUES) + CurrentAV = &AV_Descr[object_index]; + else { + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + return -1; + } + + switch (alarmack_data->eventStateAcked) + { + case EVENT_STATE_OFFNORMAL: + case EVENT_STATE_HIGH_LIMIT: + case EVENT_STATE_LOW_LIMIT: + if(CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL].bIsAcked == false) { + if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){ + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + if(datetime_compare(&CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL].Time_Stamp, + &alarmack_data->eventTimeStamp.value.dateTime) > 0) + { + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + + /* FIXME: Send ack notification */ + CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL].bIsAcked = true; + } + else { + *error_code = ERROR_CODE_INVALID_EVENT_STATE; + return -1; + } + break; + + case EVENT_STATE_FAULT: + if(CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked == false) { + if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){ + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + if(datetime_compare(&CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL].Time_Stamp, + &alarmack_data->eventTimeStamp.value.dateTime) > 0) + { + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + + /* FIXME: Send ack notification */ + CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked = true; + } + else { + *error_code = ERROR_CODE_INVALID_EVENT_STATE; + return -1; + } + break; + + case EVENT_STATE_NORMAL: + if(CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked == false) { + if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){ + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + if(datetime_compare(&CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT].Time_Stamp, + &alarmack_data->eventTimeStamp.value.dateTime) > 0) + { + *error_code = ERROR_CODE_INVALID_TIME_STAMP; + return -1; + } + + /* FIXME: Send ack notification */ + CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked = true; + } + else { + *error_code = ERROR_CODE_INVALID_EVENT_STATE; + return -1; + } + break; + + default: + return -2; + } + + return 1; +} +#endif /* defined(INTRINSIC_REPORTING) */ #ifdef TEST diff --git a/bacnet-stack/demo/object/av.h b/bacnet-stack/demo/object/av.h index 0a467ef6..2823c359 100644 --- a/bacnet-stack/demo/object/av.h +++ b/bacnet-stack/demo/object/av.h @@ -100,6 +100,9 @@ extern "C" { int Analog_Value_Event_Information(unsigned index, BACNET_GET_EVENT_INFORMATION_DATA * getevent_data); + int Analog_Value_Alarm_Ack(BACNET_ALARM_ACK_DATA * alarmack_data, + BACNET_ERROR_CODE * error_code); + void Analog_Value_Init( void); diff --git a/bacnet-stack/demo/server/main.c b/bacnet-stack/demo/server/main.c index acab1127..0975ed95 100644 --- a/bacnet-stack/demo/server/main.c +++ b/bacnet-stack/demo/server/main.c @@ -127,15 +127,10 @@ static void Init_Service_Handlers( apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, handler_device_communication_control); #if defined(INTRINSIC_REPORTING) + apdu_set_confirmed_handler(SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM, + handler_alarm_ack); apdu_set_confirmed_handler(SERVICE_CONFIRMED_GET_EVENT_INFORMATION, handler_get_event_information); - /* Set handlers for GetEventInformation - for all objects that support intrinsic reporting. */ - handler_get_event_information_set(OBJECT_ANALOG_INPUT, - Analog_Input_Event_Information); - handler_get_event_information_set(OBJECT_ANALOG_VALUE, - Analog_Value_Event_Information); - #endif /* defined(INTRINSIC_REPORTING) */ } @@ -169,7 +164,7 @@ int main( 0 }; /* address where message came from */ uint16_t pdu_len = 0; - unsigned timeout = 1000; /* milliseconds */ + unsigned timeout = 100; /* milliseconds */ time_t last_seconds = 0; time_t current_seconds = 0; uint32_t elapsed_seconds = 0; diff --git a/bacnet-stack/include/alarm_ack.h b/bacnet-stack/include/alarm_ack.h index 17181391..69af31f0 100644 --- a/bacnet-stack/include/alarm_ack.h +++ b/bacnet-stack/include/alarm_ack.h @@ -50,6 +50,14 @@ typedef struct { BACNET_TIMESTAMP ackTimeStamp; } BACNET_ALARM_ACK_DATA; +/* return +1 if alarm was acknowledged + return -1 if any error occurred + return -2 abort */ +typedef int ( + *alarm_ack_function) ( + BACNET_ALARM_ACK_DATA * alarmack_data, + BACNET_ERROR_CODE * error_code); + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/bacnet-stack/include/handlers.h b/bacnet-stack/include/handlers.h index 3ea5eaeb..5189d744 100644 --- a/bacnet-stack/include/handlers.h +++ b/bacnet-stack/include/handlers.h @@ -37,6 +37,7 @@ #include "wp.h" #include "readrange.h" #include "getevent.h" +#include "alarm_ack.h" #ifdef __cplusplus @@ -250,6 +251,10 @@ extern "C" { BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data); + void handler_alarm_ack_set( + BACNET_OBJECT_TYPE object_type, + alarm_ack_function pFunction); + void handler_conf_private_trans( uint8_t * service_request, uint16_t service_len, diff --git a/bacnet-stack/lib/Makefile b/bacnet-stack/lib/Makefile index 3c2747c5..c39d2b64 100644 --- a/bacnet-stack/lib/Makefile +++ b/bacnet-stack/lib/Makefile @@ -75,6 +75,7 @@ HANDLER_SRC = \ $(BACNET_HANDLER)/h_rr.c \ $(BACNET_HANDLER)/h_wp.c \ $(BACNET_HANDLER)/h_wpm.c \ + $(BACNET_HANDLER)/h_alarm_ack.c \ $(BACNET_HANDLER)/h_arf.c \ $(BACNET_HANDLER)/h_arf_a.c \ $(BACNET_HANDLER)/h_awf.c \