diff --git a/bacnet-stack/demo/handler/h_wpm.c b/bacnet-stack/demo/handler/h_wpm.c index a77f5189..da798f88 100644 --- a/bacnet-stack/demo/handler/h_wpm.c +++ b/bacnet-stack/demo/handler/h_wpm.c @@ -115,8 +115,16 @@ void handler_write_property_multiple( len = wpm_decode_object_property(&service_request[decode_len], service_len - decode_len, &wp_data); if (len > 0) - { + { decode_len += len; +#if PRINT_ENABLED + fprintf(stderr, + "WPM: type=%lu instance=%lu property=%lu priority=%lu index=%ld\n", + (unsigned long) wp_data.object_type, + (unsigned long) wp_data.object_instance, + (unsigned long) wp_data.object_property, + (unsigned long) wp_data.priority, (long) wp_data.array_index); +#endif if (Device_Write_Property(&wp_data) == false) { error = true; @@ -126,7 +134,7 @@ void handler_write_property_multiple( else { #if PRINT_ENABLED - fprintf(stderr, "Bad Encoding!\n"); + fprintf(stderr, "WPM: Bad Encoding!\n"); #endif wp_data.error_class = ERROR_CLASS_PROPERTY; wp_data.error_code = ERROR_CODE_OTHER; @@ -153,7 +161,7 @@ void handler_write_property_multiple( else { #if PRINT_ENABLED - fprintf(stderr, "Bad Encoding!\n"); + fprintf(stderr, "WPM: Bad Encoding!\n"); #endif wp_data.error_class = ERROR_CLASS_OBJECT; wp_data.error_code = ERROR_CODE_OTHER; @@ -172,12 +180,20 @@ void handler_write_property_multiple( apdu_len = 0; - if (error == false) + if (error == false) { apdu_len = wpm_ack_encode_apdu_init(&Handler_Transmit_Buffer[npdu_len], - service_data->invoke_id); - else + service_data->invoke_id); +#if PRINT_ENABLED + fprintf(stderr, "WPM: Sending Simple Ack!\n"); +#endif + } + else { apdu_len = wpm_error_ack_encode_apdu(&Handler_Transmit_Buffer[npdu_len], - service_data->invoke_id, &wp_data); + service_data->invoke_id, &wp_data); +#if PRINT_ENABLED + fprintf(stderr, "WPM: Sending Error!\n"); +#endif + } WPM_ABORT: diff --git a/bacnet-stack/demo/object/ai.c b/bacnet-stack/demo/object/ai.c index e08c4316..3ce52a84 100644 --- a/bacnet-stack/demo/object/ai.c +++ b/bacnet-stack/demo/object/ai.c @@ -33,9 +33,12 @@ #include "bacdef.h" #include "bacdcode.h" #include "bacenum.h" +#include "bactext.h" #include "config.h" /* the custom stuff */ +#include "device.h" #include "handlers.h" #include "timestamp.h" +#include "nc.h" #include "ai.h" @@ -613,6 +616,233 @@ bool Analog_Input_Write_Property( } +void Analog_Input_Intrinsic_Reporting(uint32_t object_instance) +{ +#if defined(INTRINSIC_REPORTING) + BACNET_EVENT_NOTIFICATION_DATA event_data; + BACNET_CHARACTER_STRING msgText; + ANALOG_INPUT_DESCR *CurrentAI; + unsigned int object_index; + uint8_t FromState; + uint8_t ToState; + float ExceededLimit; + float PresentVal; + + + object_index = Analog_Input_Instance_To_Index(object_instance); + if (object_index < MAX_ANALOG_INPUTS) + CurrentAI = &AI_Descr[object_index]; + else + return; + + /* check limits */ + if (!CurrentAI->Limit_Enable) + return; /* limits are not configured */ + + /* actual Present_Value */ + PresentVal = Analog_Input_Present_Value(object_instance); + FromState = CurrentAI->Event_State; + switch (CurrentAI->Event_State) + { + case EVENT_STATE_NORMAL: + /* A TO-OFFNORMAL event is generated under these conditions: + (a) the Present_Value must exceed the High_Limit for a minimum + period of time, specified in the Time_Delay property, and + (b) the HighLimitEnable flag must be set in the Limit_Enable property, and + (c) the TO-OFFNORMAL flag must be set in the Event_Enable property. */ + if ((PresentVal > CurrentAI->High_Limit) && + ((CurrentAI->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) == EVENT_HIGH_LIMIT_ENABLE) && + ((CurrentAI->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) == EVENT_ENABLE_TO_OFFNORMAL)) + { + if(!CurrentAI->Remaining_Time_Delay) + CurrentAI->Event_State = EVENT_STATE_HIGH_LIMIT; + else + CurrentAI->Remaining_Time_Delay--; + break; + } + + /* A TO-OFFNORMAL event is generated under these conditions: + (a) the Present_Value must exceed the Low_Limit plus the Deadband + for a minimum period of time, specified in the Time_Delay property, and + (b) the LowLimitEnable flag must be set in the Limit_Enable property, and + (c) the TO-NORMAL flag must be set in the Event_Enable property. */ + if ((PresentVal < CurrentAI->Low_Limit) && + ((CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) == EVENT_LOW_LIMIT_ENABLE) && + ((CurrentAI->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) == EVENT_ENABLE_TO_OFFNORMAL)) + { + if(!CurrentAI->Remaining_Time_Delay) + CurrentAI->Event_State = EVENT_STATE_LOW_LIMIT; + else + CurrentAI->Remaining_Time_Delay--; + break; + } + /* value of the object is still in the same event state */ + CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay; + break; + + case EVENT_STATE_HIGH_LIMIT: + /* Once exceeded, the Present_Value must fall below the High_Limit minus + the Deadband before a TO-NORMAL event is generated under these conditions: + (a) the Present_Value must fall below the High_Limit minus the Deadband + for a minimum period of time, specified in the Time_Delay property, and + (b) the HighLimitEnable flag must be set in the Limit_Enable property, and + (c) the TO-NORMAL flag must be set in the Event_Enable property. */ + if ((PresentVal < CurrentAI->High_Limit - CurrentAI->Deadband) && + ((CurrentAI->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) == EVENT_HIGH_LIMIT_ENABLE) && + ((CurrentAI->Event_Enable & EVENT_ENABLE_TO_NORMAL) == EVENT_ENABLE_TO_NORMAL)) + { + if(!CurrentAI->Remaining_Time_Delay) + CurrentAI->Event_State = EVENT_STATE_NORMAL; + else + CurrentAI->Remaining_Time_Delay--; + break; + } + /* value of the object is still in the same event state */ + CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay; + break; + + case EVENT_STATE_LOW_LIMIT: + /* Once the Present_Value has fallen below the Low_Limit, + the Present_Value must exceed the Low_Limit plus the Deadband + before a TO-NORMAL event is generated under these conditions: + (a) the Present_Value must exceed the Low_Limit plus the Deadband + for a minimum period of time, specified in the Time_Delay property, and + (b) the LowLimitEnable flag must be set in the Limit_Enable property, and + (c) the TO-NORMAL flag must be set in the Event_Enable property. */ + if ((PresentVal > CurrentAI->Low_Limit + CurrentAI->Deadband) && + ((CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) == EVENT_LOW_LIMIT_ENABLE) && + ((CurrentAI->Event_Enable & EVENT_ENABLE_TO_NORMAL) == EVENT_ENABLE_TO_NORMAL)) + { + if(!CurrentAI->Remaining_Time_Delay) + CurrentAI->Event_State = EVENT_STATE_NORMAL; + else + CurrentAI->Remaining_Time_Delay--; + break; + } + /* value of the object is still in the same event state */ + CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay; + break; + + default: + return; /* shouldn't happen */ + } /* switch (FromState) */ + + ToState = CurrentAI->Event_State; + + if (FromState != ToState) + { + /* Event_State has changed. + Need to fill only the basic parameters of this type of event. + Other parameters will be filled in common function. */ + + switch (ToState) + { + case EVENT_STATE_HIGH_LIMIT: + ExceededLimit = CurrentAI->High_Limit; + characterstring_init_ansi(&msgText, + "Goes to high limit"); + break; + + case EVENT_STATE_LOW_LIMIT: + ExceededLimit = CurrentAI->Low_Limit; + characterstring_init_ansi(&msgText, + "Goes to low limit"); + break; + + case EVENT_STATE_NORMAL: + if(FromState == EVENT_STATE_HIGH_LIMIT) { + ExceededLimit = CurrentAI->High_Limit; + characterstring_init_ansi(&msgText, + "Back to normal state from high limit"); + } + else { + ExceededLimit = CurrentAI->Low_Limit; + characterstring_init_ansi(&msgText, + "Back to normal state from low limit"); + } + break; + + default: + ExceededLimit = 0; + break; + } /* switch (ToState) */ + +#if PRINT_ENABLED + fprintf(stderr, "Event_State for (Analog-Input,%d) goes from %s to %s.\n", + object_instance, bactext_event_state_name(FromState), + bactext_event_state_name(ToState)); + +#endif /* PRINT_ENABLED) */ + + /* Event Object Identifier */ + event_data.eventObjectIdentifier.type = OBJECT_ANALOG_INPUT; + event_data.eventObjectIdentifier.instance = object_instance; + + /* Time Stamp */ + event_data.timeStamp.tag = TIME_STAMP_DATETIME; + Device_getCurrentDateTime(&event_data.timeStamp.value.dateTime); + /* fill Event_Time_Stamps */ + switch (ToState) + { + case EVENT_STATE_HIGH_LIMIT: + case EVENT_STATE_LOW_LIMIT: + CurrentAI->Event_Time_Stamps[TRANSITION_TO_OFFNORMAL] = + event_data.timeStamp.value.dateTime; + break; + + case EVENT_STATE_FAULT: + CurrentAI->Event_Time_Stamps[TRANSITION_TO_FAULT] = + event_data.timeStamp.value.dateTime; + break; + + case EVENT_STATE_NORMAL: + CurrentAI->Event_Time_Stamps[TRANSITION_TO_NORMAL] = + event_data.timeStamp.value.dateTime; + break; + } + + /* Notification Class */ + event_data.notificationClass = CurrentAI->Notification_Class; + + /* Event Type */ + event_data.eventType = EVENT_OUT_OF_RANGE; + + /* Message Text */ + event_data.messageText = &msgText; + + /* Notify Type */ + event_data.notifyType = CurrentAI->Notify_Type; + + /* From State */ + event_data.fromState = FromState; + + /* To State */ + event_data.toState = CurrentAI->Event_State; + + /* Event Values */ + event_data.notificationParams.outOfRange.exceedingValue = PresentVal; + + bitstring_init(&event_data.notificationParams.outOfRange.statusFlags); + bitstring_set_bit(&event_data.notificationParams.outOfRange.statusFlags, + STATUS_FLAG_IN_ALARM, CurrentAI->Event_State ? true : false); + bitstring_set_bit(&event_data.notificationParams.outOfRange.statusFlags, + STATUS_FLAG_FAULT, false); + bitstring_set_bit(&event_data.notificationParams.outOfRange.statusFlags, + STATUS_FLAG_OVERRIDDEN, false); + bitstring_set_bit(&event_data.notificationParams.outOfRange.statusFlags, + STATUS_FLAG_OUT_OF_SERVICE, CurrentAI->Out_Of_Service); + + event_data.notificationParams.outOfRange.deadband = CurrentAI->Deadband; + + event_data.notificationParams.outOfRange.exceededLimit = ExceededLimit; + + /* add data from notification class */ + Notification_Class_common_reporting_function(&event_data); + } +#endif /* defined(INTRINSIC_REPORTING) */ +} + + #ifdef TEST #include #include diff --git a/bacnet-stack/demo/object/ai.h b/bacnet-stack/demo/object/ai.h index e16bb880..b240b376 100644 --- a/bacnet-stack/demo/object/ai.h +++ b/bacnet-stack/demo/object/ai.h @@ -107,6 +107,8 @@ extern "C" { uint32_t object_instance, float value); + void Analog_Input_Intrinsic_Reporting(uint32_t object_instance); + void Analog_Input_Init( void); diff --git a/bacnet-stack/demo/object/av.c b/bacnet-stack/demo/object/av.c index 41a0d704..cea9e1bf 100644 --- a/bacnet-stack/demo/object/av.c +++ b/bacnet-stack/demo/object/av.c @@ -878,12 +878,12 @@ void Analog_Value_Intrinsic_Reporting(uint32_t object_instance) break; } /* switch (ToState) */ -#if defined(PRINT_ENABLED) +#if PRINT_ENABLED fprintf(stderr, "Event_State for (Analog-Value,%d) goes from %s to %s.\n", object_instance, bactext_event_state_name(FromState), bactext_event_state_name(ToState)); -#endif /* defined(PRINT_ENABLED) */ +#endif /* PRINT_ENABLED */ /* Event Object Identifier */ event_data.eventObjectIdentifier.type = OBJECT_ANALOG_VALUE; diff --git a/bacnet-stack/demo/object/device.c b/bacnet-stack/demo/object/device.c index 35288e29..dec497e0 100644 --- a/bacnet-stack/demo/object/device.c +++ b/bacnet-stack/demo/object/device.c @@ -93,7 +93,7 @@ static object_functions_t Object_Table[] = { Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, Analog_Input_Object_Name, Analog_Input_Read_Property, Analog_Input_Write_Property, Analog_Input_Property_Lists, - NULL, NULL, NULL, NULL}, { + NULL, NULL, NULL, Analog_Input_Intrinsic_Reporting}, { OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance, Analog_Value_Object_Name, Analog_Value_Read_Property, @@ -1497,7 +1497,7 @@ void Device_local_reporting(void) objects_count = Device_Object_List_Count(); /* loop for all objects */ - for (idx = 0; idx < objects_count; idx++) + for (idx = 1; idx < objects_count; idx++) { Device_Object_List_Identifier(idx, &object_type, &object_instance); diff --git a/bacnet-stack/src/wpm.c b/bacnet-stack/src/wpm.c index 43f36df4..ea2804db 100644 --- a/bacnet-stack/src/wpm.c +++ b/bacnet-stack/src/wpm.c @@ -44,7 +44,7 @@ int wpm_decode_object_id(uint8_t * apdu, uint16_t apdu_len, if((apdu )&& (apdu_len)) { - /* Context tag 0 - Object ID */ + /* Context tag 0 - Object ID */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if(tag_number == 0) { @@ -78,7 +78,7 @@ int wpm_decode_object_property(uint8_t * apdu, wp_data->priority = BACNET_NO_PRIORITY; wp_data->application_data_len = 0; - /* tag 0 - Property Identifier */ + /* tag 0 - Property Identifier */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if(tag_number == 0) { @@ -88,7 +88,7 @@ int wpm_decode_object_property(uint8_t * apdu, else return -1; - /* tag 1 - Property Array Index - optional */ + /* tag 1 - Property Array Index - optional */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if(tag_number ==1) { @@ -97,7 +97,7 @@ int wpm_decode_object_property(uint8_t * apdu, len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); } - /* tag 2 - Property Value */ + /* tag 2 - Property Value */ if((tag_number == 2) && (decode_is_opening_tag(&apdu[len-1]))) { len--; @@ -105,20 +105,20 @@ int wpm_decode_object_property(uint8_t * apdu, apdu_len - len, wp_data->object_property); len++; - /* copy application data */ + /* copy application data */ for(i = 0; i < wp_data->application_data_len; i++) wp_data->application_data[i] = apdu[len+i]; len += wp_data->application_data_len; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); - /* closing tag 2 */ + /* closing tag 2 */ if((tag_number != 2) &&(decode_is_closing_tag(&apdu[len-1]))) return -1; } else return -1; - /* tag 3 - Priority - optional */ + /* tag 3 - Priority - optional */ len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); if(tag_number == 3) {