diff --git a/bacnet-stack/demo/handler/h_wpm.c b/bacnet-stack/demo/handler/h_wpm.c index 4eb8f2d9..a77f5189 100644 --- a/bacnet-stack/demo/handler/h_wpm.c +++ b/bacnet-stack/demo/handler/h_wpm.c @@ -97,7 +97,7 @@ void handler_write_property_multiple( decode_len = 0; do { - /* decode Object Identifier */ + /* decode Object Identifier */ len = wpm_decode_object_id(&service_request[decode_len], service_len - decode_len, &wp_data); if (len > 0) @@ -105,13 +105,13 @@ void handler_write_property_multiple( uint8_t tag_number = 0; decode_len += len; - /* Opening tag 1 - List of Properties */ + /* Opening tag 1 - List of Properties */ if (decode_is_opening_tag_number(&service_request[decode_len++], 1)) { do { - /* decode a 'Property Identifier'; (3) an optional 'Property Array Index'; */ - /* (4) a 'Property Value'; and (5) an optional 'Priority'. */ + /* decode a 'Property Identifier'; (3) an optional 'Property Array Index' */ + /* (4) a 'Property Value'; and (5) an optional 'Priority'. */ len = wpm_decode_object_property(&service_request[decode_len], service_len - decode_len, &wp_data); if (len > 0) @@ -120,7 +120,7 @@ void handler_write_property_multiple( if (Device_Write_Property(&wp_data) == false) { error = true; - break; /* do while (decoding List of Properties) */ + break; /* do while (decoding List of Properties) */ } } else @@ -131,23 +131,23 @@ void handler_write_property_multiple( wp_data.error_class = ERROR_CLASS_PROPERTY; wp_data.error_code = ERROR_CODE_OTHER; error = true; - break; /* do while (decoding List of Properties) */ + break; /* do while (decoding List of Properties) */ } - /* Closing tag 1 - List of Properties */ + /* Closing tag 1 - List of Properties */ if (decode_is_closing_tag_number(&service_request[decode_len], 1)) { tag_number = 1; decode_len++; } else - tag_number = 0; /* it was not tag 1, decode next Property Identifier ... */ + tag_number = 0; /* it was not tag 1, decode next Property Identifier ... */ } - while(tag_number != 1); /* end decoding List of Properties for "that" object */ + while(tag_number != 1); /* end decoding List of Properties for "that" object */ if (error) - break; /*do while (decode service request) */ + break; /*do while (decode service request) */ } } else @@ -158,7 +158,7 @@ void handler_write_property_multiple( wp_data.error_class = ERROR_CLASS_OBJECT; wp_data.error_code = ERROR_CODE_OTHER; error = true; - break; /*do while (decode service request) */ + break; /*do while (decode service request) */ } } while(decode_len < service_len); diff --git a/bacnet-stack/demo/object/ai.c b/bacnet-stack/demo/object/ai.c index 8291456c..e08c4316 100644 --- a/bacnet-stack/demo/object/ai.c +++ b/bacnet-stack/demo/object/ai.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 @@ -28,17 +29,22 @@ #include #include #include + #include "bacdef.h" #include "bacdcode.h" #include "bacenum.h" #include "config.h" /* the custom stuff */ +#include "handlers.h" +#include "timestamp.h" #include "ai.h" + #ifndef MAX_ANALOG_INPUTS #define MAX_ANALOG_INPUTS 4 #endif -static float Present_Value[MAX_ANALOG_INPUTS]; + +ANALOG_INPUT_DESCR AI_Descr[MAX_ANALOG_INPUTS]; /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Properties_Required[] = { @@ -55,6 +61,18 @@ static const int Properties_Required[] = { static const int Properties_Optional[] = { PROP_DESCRIPTION, +#if defined(INTRINSIC_REPORTING) + PROP_TIME_DELAY, + PROP_NOTIFICATION_CLASS, + PROP_HIGH_LIMIT, + PROP_LOW_LIMIT, + PROP_DEADBAND, + PROP_LIMIT_ENABLE, + PROP_EVENT_ENABLE, + PROP_ACKED_TRANSITIONS, + PROP_NOTIFY_TYPE, + PROP_EVENT_TIME_STAMPS, +#endif -1 }; @@ -80,6 +98,29 @@ void Analog_Input_Property_Lists( return; } + +void Analog_Input_Init( + void) +{ + unsigned i, j; + + for (i = 0; i < MAX_ANALOG_INPUTS; i++) { + AI_Descr[i].Present_Value = 0.0f; + AI_Descr[i].Out_Of_Service = false; + AI_Descr[i].Units = UNITS_PERCENT; + AI_Descr[i].Reliability = RELIABILITY_NO_FAULT_DETECTED; +#if defined(INTRINSIC_REPORTING) + AI_Descr[i].Event_State = EVENT_STATE_NORMAL; + /* notification class not connected */ + AI_Descr[i].Notification_Class = BACNET_MAX_INSTANCE; + /* initialize Event time stamps using wildcards */ + for (j = 0; j < MAX_BACNET_EVENT_TRANSITION; j++) { + datetime_wildcard_set(&AI_Descr[i].Event_Time_Stamps[j]); + } +#endif + } +} + /* we simply have 0-n object instances. Yours might be */ /* more complex, and then you need validate that the */ /* given instance exists */ @@ -134,7 +175,7 @@ float Analog_Input_Present_Value( index = Analog_Input_Instance_To_Index(object_instance); if (index < MAX_ANALOG_INPUTS) { - value = Present_Value[index]; + value = AI_Descr[index].Present_Value; } return value; @@ -148,7 +189,7 @@ void Analog_Input_Present_Value_Set( index = Analog_Input_Instance_To_Index(object_instance); if (index < MAX_ANALOG_INPUTS) { - Present_Value[index] = value; + AI_Descr[index].Present_Value = value; } } @@ -174,15 +215,26 @@ bool Analog_Input_Object_Name( int Analog_Input_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { + int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; + ANALOG_INPUT_DESCR *CurrentAI; + unsigned object_index = 0; + unsigned i = 0; uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } + + object_index = Analog_Input_Instance_To_Index(rpdata->object_instance); + if (object_index < MAX_ANALOG_INPUTS) + CurrentAI = &AI_Descr[object_index]; + else + return BACNET_STATUS_ERROR; + apdu = rpdata->application_data; switch ((int) rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: @@ -190,39 +242,168 @@ int Analog_Input_Read_Property( encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT, rpdata->object_instance); break; + case PROP_OBJECT_NAME: case PROP_DESCRIPTION: Analog_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; + case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_INPUT); break; + case PROP_PRESENT_VALUE: apdu_len = encode_application_real(&apdu[0], Analog_Input_Present_Value(rpdata->object_instance)); break; + case PROP_STATUS_FLAGS: bitstring_init(&bit_string); +#if defined(INTRINSIC_REPORTING) + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, + CurrentAI->Event_State ? true : false); +#else bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); +#endif bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); - bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, CurrentAI->Out_Of_Service); + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; + case PROP_EVENT_STATE: - apdu_len = - encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); +#if defined(INTRINSIC_REPORTING) + apdu_len = encode_application_enumerated(&apdu[0], + CurrentAI->Event_State); +#else + apdu_len = encode_application_enumerated(&apdu[0], + EVENT_STATE_NORMAL); +#endif break; + + case PROP_RELIABILITY: + apdu_len = encode_application_enumerated(&apdu[0], CurrentAI->Reliability); + break; + case PROP_OUT_OF_SERVICE: - apdu_len = encode_application_boolean(&apdu[0], false); + apdu_len = encode_application_boolean(&apdu[0], CurrentAI->Out_Of_Service); break; + case PROP_UNITS: - apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT); + apdu_len = encode_application_enumerated(&apdu[0], CurrentAI->Units); break; + +#if defined(INTRINSIC_REPORTING) + case PROP_TIME_DELAY: + apdu_len = encode_application_unsigned(&apdu[0], CurrentAI->Time_Delay); + break; + + case PROP_NOTIFICATION_CLASS: + apdu_len = encode_application_unsigned(&apdu[0], CurrentAI->Notification_Class); + break; + + case PROP_HIGH_LIMIT: + apdu_len = encode_application_real(&apdu[0], CurrentAI->High_Limit); + break; + + case PROP_LOW_LIMIT: + apdu_len = encode_application_real(&apdu[0], CurrentAI->Low_Limit); + break; + + case PROP_DEADBAND: + apdu_len = encode_application_real(&apdu[0], CurrentAI->Deadband); + break; + + case PROP_LIMIT_ENABLE: + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, 0, + (CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE ) ? true : false ); + bitstring_set_bit(&bit_string, 1, + (CurrentAI->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) ? true : false ); + + apdu_len = encode_application_bitstring(&apdu[0],&bit_string); + break; + + case PROP_EVENT_ENABLE: + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, + (CurrentAI->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) ? true : false ); + bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, + (CurrentAI->Event_Enable & EVENT_ENABLE_TO_FAULT ) ? true : false ); + bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, + (CurrentAI->Event_Enable & EVENT_ENABLE_TO_NORMAL ) ? true : false ); + + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + + case PROP_ACKED_TRANSITIONS: + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, true); + bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, true); + bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, true); + + /* Fixme: finish it */ + + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + + case PROP_NOTIFY_TYPE: + apdu_len = encode_application_enumerated(&apdu[0], + CurrentAI->Notify_Type ? NOTIFY_EVENT : NOTIFY_ALARM); + break; + + case PROP_EVENT_TIME_STAMPS: + /* Array element zero is the number of elements in the array */ + if (rpdata->array_index == 0) + apdu_len = encode_application_unsigned(&apdu[0], + MAX_BACNET_EVENT_TRANSITION); + /* if no index was specified, then try to encode the entire list */ + /* into one packet. */ + else if (rpdata->array_index == BACNET_ARRAY_ALL) { + for (i = 0; i < MAX_BACNET_EVENT_TRANSITION; i++) {; + len = encode_opening_tag(&apdu[apdu_len], + TIME_STAMP_DATETIME); + len += encode_application_date(&apdu[apdu_len + len], + &CurrentAI->Event_Time_Stamps[i].date); + len += encode_application_time(&apdu[apdu_len + len], + &CurrentAI->Event_Time_Stamps[i].time); + len += encode_closing_tag(&apdu[apdu_len + len], + TIME_STAMP_DATETIME); + + /* add it if we have room */ + if ((apdu_len + len) < MAX_APDU) + apdu_len += len; + else { + rpdata->error_class = ERROR_CLASS_SERVICES; + rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; + apdu_len = BACNET_STATUS_ERROR; + break; + } + } + } + else if (rpdata->array_index <= MAX_BACNET_EVENT_TRANSITION) { + apdu_len = encode_opening_tag(&apdu[apdu_len], + TIME_STAMP_DATETIME); + apdu_len += encode_application_date(&apdu[apdu_len], + &CurrentAI->Event_Time_Stamps[rpdata->array_index].date); + apdu_len += encode_application_time(&apdu[apdu_len], + &CurrentAI->Event_Time_Stamps[rpdata->array_index].time); + apdu_len += encode_closing_tag(&apdu[apdu_len], + TIME_STAMP_DATETIME); + } + else { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + } + break; +#endif + case 9997: /* test case for real encoding-decoding unsigned value correctly */ apdu_len = encode_application_real(&apdu[0], 90.510F); @@ -242,20 +423,196 @@ int Analog_Input_Read_Property( break; } /* only array properties can have array options */ - if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) { + if ((apdu_len >= 0) && + (rpdata->object_property != PROP_EVENT_TIME_STAMPS) && + (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; + rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; } -void Analog_Input_Init( - void) +/* returns true if successful */ +bool Analog_Input_Write_Property( + BACNET_WRITE_PROPERTY_DATA * wp_data) { + bool status = false; /* return value */ + unsigned int object_index = 0; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; + ANALOG_INPUT_DESCR *CurrentAI; + + /* decode the some of the request */ + len = + bacapp_decode_application_data(wp_data->application_data, + wp_data->application_data_len, &value); + /* FIXME: len < application_data_len: more data? */ + if (len < 0) { + /* error while decoding - a value larger than we can handle */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + return false; + } + + object_index = Analog_Input_Instance_To_Index(wp_data->object_instance); + if (object_index < MAX_ANALOG_INPUTS) + CurrentAI = &AI_Descr[object_index]; + else + return false; + + switch (wp_data->object_property) { + case PROP_PRESENT_VALUE: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + if (CurrentAI->Out_Of_Service == true) { + Analog_Input_Present_Value_Set(wp_data->object_instance, + value.type.Real); + } + else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + status = false; + } + } + break; + + case PROP_OUT_OF_SERVICE: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, + &wp_data->error_class, &wp_data->error_code); + if (status) { + CurrentAI->Out_Of_Service = value.type.Boolean; + } + break; + + case PROP_UNITS: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, + &wp_data->error_class, &wp_data->error_code); + if (status) { + CurrentAI->Units = value.type.Enumerated; + } + break; + +#if defined(INTRINSIC_REPORTING) + case PROP_TIME_DELAY: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + CurrentAI->Time_Delay = value.type.Unsigned_Int; + CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay; + } + break; + + case PROP_NOTIFICATION_CLASS: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + CurrentAI->Notification_Class = value.type.Unsigned_Int; + } + break; + + case PROP_HIGH_LIMIT: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + CurrentAI->High_Limit = value.type.Real; + } + break; + + case PROP_LOW_LIMIT: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + CurrentAI->Low_Limit = value.type.Real; + } + break; + + case PROP_DEADBAND: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + CurrentAI->Deadband = value.type.Real; + } + break; + + case PROP_LIMIT_ENABLE: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_BIT_STRING, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + if(value.type.Bit_String.bits_used == 2) { + CurrentAI->Limit_Enable = value.type.Bit_String.value[0]; + } + else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + status = false; + } + } + break; + + case PROP_EVENT_ENABLE: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_BIT_STRING, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + if(value.type.Bit_String.bits_used == 3) { + CurrentAI->Event_Enable = value.type.Bit_String.value[0]; + } + else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + status = false; + } + } + break; + + case PROP_NOTIFY_TYPE: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + if(value.type.Bit_String.bits_used > NOTIFY_EVENT) { + CurrentAI->Event_Enable = value.type.Enumerated; + } + else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + status = false; + } + } + break; +#endif + + default: + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } + + return status; } + #ifdef TEST #include #include diff --git a/bacnet-stack/demo/object/ai.h b/bacnet-stack/demo/object/ai.h index 3ea8cadd..e16bb880 100644 --- a/bacnet-stack/demo/object/ai.h +++ b/bacnet-stack/demo/object/ai.h @@ -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 @@ -34,6 +35,32 @@ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ + + typedef struct analog_input_descr { + uint8_t Event_State : 3; + float Present_Value; + BACNET_RELIABILITY Reliability; + bool Out_Of_Service; + uint8_t Units; +#if defined(INTRINSIC_REPORTING) + uint32_t Time_Delay; + uint32_t Notification_Class; + float High_Limit; + float Low_Limit; + float Deadband; + uint8_t Limit_Enable : 2; + uint8_t Event_Enable : 3; + uint8_t Acked_Transitions : 3; + uint8_t Notify_Type : 1; + BACNET_DATE_TIME Event_Time_Stamps[MAX_BACNET_EVENT_TRANSITION]; + /* time to generate event notification */ + uint32_t Remaining_Time_Delay; +#endif + } ANALOG_INPUT_DESCR; + + + + void Analog_Input_Property_Lists( const int **pRequired, const int **pOptional, diff --git a/bacnet-stack/demo/object/av.c b/bacnet-stack/demo/object/av.c index dd06006e..41a0d704 100644 --- a/bacnet-stack/demo/object/av.c +++ b/bacnet-stack/demo/object/av.c @@ -35,6 +35,7 @@ #include "bacdcode.h" #include "bacenum.h" #include "bacapp.h" +#include "bactext.h" #include "config.h" /* the custom stuff */ #include "wp.h" #include "rp.h" @@ -435,7 +436,7 @@ int Analog_Value_Read_Property( bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, true); bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, true); - /*/ Fixme: finish it */ + /* Fixme: finish it */ apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; @@ -877,6 +878,12 @@ void Analog_Value_Intrinsic_Reporting(uint32_t object_instance) break; } /* switch (ToState) */ +#if defined(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) */ /* 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 ae9591af..35288e29 100644 --- a/bacnet-stack/demo/object/device.c +++ b/bacnet-stack/demo/object/device.c @@ -92,7 +92,7 @@ static object_functions_t Object_Table[] = { OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, Analog_Input_Object_Name, Analog_Input_Read_Property, - NULL, Analog_Input_Property_Lists, + Analog_Input_Write_Property, Analog_Input_Property_Lists, NULL, NULL, NULL, NULL}, { OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance, @@ -1485,7 +1485,7 @@ bool Device_Encode_Value_List( } -void Device_local_reporting(uint32_t milliseconds) +void Device_local_reporting(void) { #if defined(INTRINSIC_REPORTING) struct object_functions *pObject; diff --git a/bacnet-stack/demo/object/device.h b/bacnet-stack/demo/object/device.h index 474b71f5..b559027a 100644 --- a/bacnet-stack/demo/object/device.h +++ b/bacnet-stack/demo/object/device.h @@ -337,7 +337,7 @@ extern "C" { bool Device_Write_Property_Local( BACNET_WRITE_PROPERTY_DATA * wp_data); - void Device_local_reporting(uint32_t milliseconds); + void Device_local_reporting(void); /* Prototypes for Routing functionality in the Device Object. * Enable by defining BAC_ROUTING in config.h and including gw_device.c diff --git a/bacnet-stack/demo/object/nc.c b/bacnet-stack/demo/object/nc.c index df9a70ae..e6dcdfae 100644 --- a/bacnet-stack/demo/object/nc.c +++ b/bacnet-stack/demo/object/nc.c @@ -1,894 +1,866 @@ -/************************************************************************** -* -* 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 -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ -#include -#include -#include -#include - -#include "address.h" -#include "bacdef.h" -#include "bacdcode.h" -#include "bacenum.h" -#include "bacapp.h" -#include "client.h" -#include "config.h" -#include "device.h" -#include "event.h" -#include "handlers.h" -#include "txbuf.h" -#include "wp.h" -#include "nc.h" - - -#ifndef MAX_NOTIFICATION_CLASSES -#define MAX_NOTIFICATION_CLASSES 2 -#endif - - -#if defined(INTRINSIC_REPORTING) -static NOTIFICATION_CLASS_INFO NC_Info[MAX_NOTIFICATION_CLASSES]; - -/* These three arrays are used by the ReadPropertyMultiple handler */ -static const int Notification_Properties_Required[] = -{ - PROP_OBJECT_IDENTIFIER, - PROP_OBJECT_NAME, - PROP_OBJECT_TYPE, - PROP_NOTIFICATION_CLASS, - PROP_PRIORITY, - PROP_ACK_REQUIRED, - PROP_RECIPIENT_LIST, - -1 -}; - -static const int Notification_Properties_Optional[] = -{ - PROP_DESCRIPTION, - -1 -}; - -static const int Notification_Properties_Proprietary[] = -{ - -1 -}; - -void Notification_Class_Property_Lists( - const int **pRequired, - const int **pOptional, - const int **pProprietary) -{ - if (pRequired) - *pRequired = Notification_Properties_Required; - if (pOptional) - *pOptional = Notification_Properties_Optional; - if (pProprietary) - *pProprietary = Notification_Properties_Proprietary; - return; -} - -void Notification_Class_Init(void) -{ - uint8_t NotifyIdx = 0; - - for (NotifyIdx = 0; NotifyIdx < MAX_NOTIFICATION_CLASSES; NotifyIdx++) - { - /* init with zeros */ - memset(&NC_Info[NotifyIdx], 0x00, sizeof(NOTIFICATION_CLASS_INFO)); - /* set the basic parameters */ - NC_Info[NotifyIdx].Ack_Required = 0; - NC_Info[NotifyIdx].Priority[0] = 255; /* The lowest priority for Normal message. */ - NC_Info[NotifyIdx].Priority[1] = 255; /* The lowest priority for Normal message. */ - NC_Info[NotifyIdx].Priority[2] = 255; /* The lowest priority for Normal message. */ - } - - /* init with special values for tests */ -/* NC_Info[0].Ack_Required = TRANSITION_TO_NORMAL_MASKED; */ -/* NC_Info[0].Priority[0] = 248; */ -/* NC_Info[0].Priority[1] = 192; */ -/* NC_Info[0].Priority[2] = 200; */ -/* NC_Info[0].Recipient_List[0].ValidDays = 0x1F; /* from monday to friday */ */ -/* NC_Info[0].Recipient_List[0].FromTime.hour = 6; */ -/* NC_Info[0].Recipient_List[0].FromTime.min = 15; */ -/* NC_Info[0].Recipient_List[0].FromTime.sec = 10; */ -/* NC_Info[0].Recipient_List[0].FromTime.hundredths = 0; */ -/* NC_Info[0].Recipient_List[0].ToTime.hour = 23; */ -/* NC_Info[0].Recipient_List[0].ToTime.min = 48; */ -/* NC_Info[0].Recipient_List[0].ToTime.sec = 59; */ -/* NC_Info[0].Recipient_List[0].ToTime.hundredths = 0; */ -/* NC_Info[0].Recipient_List[0].Recipient.RecipientType = RECIPIENT_TYPE_ADDRESS; */ -/* NC_Info[0].Recipient_List[0].Recipient._.Address.mac[0] = 0xC0; */ -/* NC_Info[0].Recipient_List[0].Recipient._.Address.mac[1] = 0xA8; */ -/* NC_Info[0].Recipient_List[0].Recipient._.Address.mac[2] = 0x01; */ -/* NC_Info[0].Recipient_List[0].Recipient._.Address.mac[3] = 0xFF; */ -/* NC_Info[0].Recipient_List[0].Recipient._.Address.mac[4] = 0xBA; */ -/* NC_Info[0].Recipient_List[0].Recipient._.Address.mac[5] = 0xC0; */ -/* NC_Info[0].Recipient_List[0].Recipient._.Address.mac_len = 6; */ -/* NC_Info[0].Recipient_List[0].ProcessIdentifier = 112233; */ -/* NC_Info[0].Recipient_List[0].ConfirmedNotify = true; */ -/* NC_Info[0].Recipient_List[0].Transitions = */ -/* TRANSITION_TO_OFFNORMAL_MASKED | TRANSITION_TO_NORMAL_MASKED; */ - - - return; -} - - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need validate that the */ -/* given instance exists */ -bool Notification_Class_Valid_Instance( - uint32_t object_instance) -{ - unsigned int index; - - index = Notification_Class_Instance_To_Index(object_instance); - if (index < MAX_NOTIFICATION_CLASSES) - return true; - - return false; -} - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then count how many you have */ -unsigned Notification_Class_Count(void) -{ - return MAX_NOTIFICATION_CLASSES; -} - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need to return the instance */ -/* that correlates to the correct index */ -uint32_t Notification_Class_Index_To_Instance(unsigned index) -{ - return index; -} - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need to return the index */ -/* that correlates to the correct instance number */ -unsigned Notification_Class_Instance_To_Index( - uint32_t object_instance) -{ - unsigned index = MAX_NOTIFICATION_CLASSES; - - if (object_instance < MAX_NOTIFICATION_CLASSES) - index = object_instance; - - return index; -} - -bool Notification_Class_Object_Name( - uint32_t object_instance, - BACNET_CHARACTER_STRING *object_name) -{ - static char text_string[32] = ""; /* okay for single thread */ - unsigned int index; - bool status = false; - - index = Notification_Class_Instance_To_Index(object_instance); - if (index < MAX_NOTIFICATION_CLASSES) { - sprintf(text_string, "NOTIFICATION CLASS %lu", (unsigned long) index); - status = characterstring_init_ansi(object_name, text_string); - } - - return status; -} - - - -int Notification_Class_Read_Property( - BACNET_READ_PROPERTY_DATA * rpdata) -{ - NOTIFICATION_CLASS_INFO *CurrentNotify; - BACNET_CHARACTER_STRING char_string; - BACNET_OCTET_STRING octet_string; - BACNET_BIT_STRING bit_string; - uint8_t *apdu = NULL; - uint8_t u8Val; - int idx; - int apdu_len = 0; /* return value */ - - - if ((rpdata == NULL) || (rpdata->application_data == NULL) || - (rpdata->application_data_len == 0)) { - return 0; - } - - apdu = rpdata->application_data; - CurrentNotify = &NC_Info[Notification_Class_Instance_To_Index(rpdata->object_instance)]; - - switch (rpdata->object_property) - { - case PROP_OBJECT_IDENTIFIER: - apdu_len = - encode_application_object_id(&apdu[0], OBJECT_NOTIFICATION_CLASS, - rpdata->object_instance); - break; - - case PROP_OBJECT_NAME: - case PROP_DESCRIPTION: - Notification_Class_Object_Name(rpdata->object_instance, &char_string); - apdu_len = - encode_application_character_string(&apdu[0], &char_string); - break; - - case PROP_OBJECT_TYPE: - apdu_len = - encode_application_enumerated(&apdu[0], OBJECT_NOTIFICATION_CLASS); - break; - - case PROP_NOTIFICATION_CLASS: - apdu_len += encode_application_unsigned(&apdu[0], rpdata->object_instance); - break; - - case PROP_PRIORITY: - if (rpdata->array_index == 0) - apdu_len += encode_application_unsigned(&apdu[0], 3); - else - { - if (rpdata->array_index == BACNET_ARRAY_ALL) - { - /* TO-OFFNORMAL */ - apdu_len += encode_application_unsigned(&apdu[apdu_len], - CurrentNotify->Priority[0]); - /* TO-FAULT */ - apdu_len += encode_application_unsigned(&apdu[apdu_len], - CurrentNotify->Priority[1]); - /* TO-NORMAL */ - apdu_len += encode_application_unsigned(&apdu[apdu_len], - CurrentNotify->Priority[2]); - } - else if (rpdata->array_index <= 3) - { - apdu_len += encode_application_unsigned(&apdu[apdu_len], - CurrentNotify->Priority[rpdata->array_index - 1]); - } - else - { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = -1; - } - } - break; - - case PROP_ACK_REQUIRED: - u8Val = CurrentNotify->Ack_Required; - - bitstring_init(&bit_string); - bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, - (u8Val & TRANSITION_TO_OFFNORMAL_MASKED) ? true : false ); - bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, - (u8Val & TRANSITION_TO_FAULT_MASKED ) ? true : false ); - bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, - (u8Val & TRANSITION_TO_NORMAL_MASKED ) ? true : false ); - /* encode bitstring */ - apdu_len += encode_application_bitstring(&apdu[apdu_len], &bit_string); - break; - - case PROP_RECIPIENT_LIST: - /* encode all entry of Recipient_List */ - for (idx = 0; idx < NC_MAX_RECIPIENTS; idx++) - { - BACNET_DESTINATION *RecipientEntry; - int i = 0; - - /* get pointer of current element for Recipient_List - easier for use */ - RecipientEntry = &CurrentNotify->Recipient_List[idx]; - if (RecipientEntry->Recipient.RecipientType != RECIPIENT_TYPE_NOTINITIALIZED) - { - /* Valid Days - BACnetDaysOfWeek - [bitstring] monday-sunday */ - u8Val = 0x01; - bitstring_init(&bit_string); - - for (i = 0; i < MAX_BACNET_DAYS_OF_WEEK; i++) - { - if (RecipientEntry->ValidDays & u8Val) - bitstring_set_bit(&bit_string, i, true); - else - bitstring_set_bit(&bit_string, i, false); - u8Val <<= 1; /* next day */ - } - apdu_len += encode_application_bitstring(&apdu[apdu_len],&bit_string); - - /* From Time */ - apdu_len += encode_application_time(&apdu[apdu_len], - &RecipientEntry->FromTime); - - /* To Time */ - apdu_len += encode_application_time(&apdu[apdu_len], - &RecipientEntry->ToTime); - - /* - BACnetRecipient ::= CHOICE { - device [0] BACnetObjectIdentifier, - address [1] BACnetAddress - } */ - - /* CHOICE - device [0] BACnetObjectIdentifier */ - if(RecipientEntry->Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) - { - apdu_len += encode_context_object_id(&apdu[apdu_len], 0, OBJECT_DEVICE, - RecipientEntry->Recipient._.DeviceIdentifier); - } - /* CHOICE - address [1] BACnetAddress */ - else if (RecipientEntry->Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) - { - /* opening tag 1 */ - apdu_len += encode_opening_tag(&apdu[apdu_len], 1); - /* network-number Unsigned16, */ - apdu_len += encode_application_unsigned(&apdu[apdu_len], - RecipientEntry->Recipient._.Address.net); - - /* mac-address OCTET STRING */ - if (RecipientEntry->Recipient._.Address.net) - { - octetstring_init(&octet_string, - RecipientEntry->Recipient._.Address.adr, - RecipientEntry->Recipient._.Address.len); - } - else - { - octetstring_init(&octet_string, - RecipientEntry->Recipient._.Address.mac, - RecipientEntry->Recipient._.Address.mac_len); - } - apdu_len += encode_application_octet_string(&apdu[apdu_len], &octet_string); - - /* closing tag 1 */ - apdu_len += encode_closing_tag(&apdu[apdu_len], 1); - - } - else {;} /* shouldn't happen */ - - /* Process Identifier - Unsigned32 */ - apdu_len += encode_application_unsigned(&apdu[apdu_len], - RecipientEntry->ProcessIdentifier); - - /* Issue Confirmed Notifications - boolean */ - apdu_len += encode_application_boolean(&apdu[apdu_len], - RecipientEntry->ConfirmedNotify); - - /* Transitions - BACnet Event Transition Bits [bitstring] */ - u8Val = RecipientEntry->Transitions; - - bitstring_init(&bit_string); - bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, - (u8Val & TRANSITION_TO_OFFNORMAL_MASKED) ? true : false ); - bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, - (u8Val & TRANSITION_TO_FAULT_MASKED ) ? true : false ); - bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, - (u8Val & TRANSITION_TO_NORMAL_MASKED ) ? true : false ); - - apdu_len += encode_application_bitstring(&apdu[apdu_len], &bit_string); - } - } - break; - - default: - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; - apdu_len = -1; - break; - } - - /* only array properties can have array options */ - if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY) && - (rpdata->array_index != BACNET_ARRAY_ALL)) - { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; - apdu_len = BACNET_STATUS_ERROR; - } - - return apdu_len; -} - - -bool Notification_Class_Write_Property( - BACNET_WRITE_PROPERTY_DATA * wp_data) -{ - NOTIFICATION_CLASS_INFO *CurrentNotify; - NOTIFICATION_CLASS_INFO TmpNotify; - BACNET_APPLICATION_DATA_VALUE value; - bool status = false; - int iOffset = 0; - uint8_t idx = 0; - int len = 0; - - - - CurrentNotify = &NC_Info[Notification_Class_Instance_To_Index(wp_data->object_instance)]; - +/************************************************************************** +* +* 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 +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ +#include +#include +#include +#include + +#include "address.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "bacapp.h" +#include "client.h" +#include "config.h" +#include "device.h" +#include "event.h" +#include "handlers.h" +#include "txbuf.h" +#include "wp.h" +#include "nc.h" + + +#ifndef MAX_NOTIFICATION_CLASSES +#define MAX_NOTIFICATION_CLASSES 2 +#endif + + +#if defined(INTRINSIC_REPORTING) +static NOTIFICATION_CLASS_INFO NC_Info[MAX_NOTIFICATION_CLASSES]; + +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Notification_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_NOTIFICATION_CLASS, + PROP_PRIORITY, + PROP_ACK_REQUIRED, + PROP_RECIPIENT_LIST, + -1 +}; + +static const int Notification_Properties_Optional[] = +{ + PROP_DESCRIPTION, + -1 +}; + +static const int Notification_Properties_Proprietary[] = +{ + -1 +}; + +void Notification_Class_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (pRequired) + *pRequired = Notification_Properties_Required; + if (pOptional) + *pOptional = Notification_Properties_Optional; + if (pProprietary) + *pProprietary = Notification_Properties_Proprietary; + return; +} + +void Notification_Class_Init(void) +{ + uint8_t NotifyIdx = 0; + + for (NotifyIdx = 0; NotifyIdx < MAX_NOTIFICATION_CLASSES; NotifyIdx++) + { + /* init with zeros */ + memset(&NC_Info[NotifyIdx], 0x00, sizeof(NOTIFICATION_CLASS_INFO)); + /* set the basic parameters */ + NC_Info[NotifyIdx].Ack_Required = 0; + NC_Info[NotifyIdx].Priority[0] = 255; /* The lowest priority for Normal message. */ + NC_Info[NotifyIdx].Priority[1] = 255; /* The lowest priority for Normal message. */ + NC_Info[NotifyIdx].Priority[2] = 255; /* The lowest priority for Normal message. */ + } + + return; +} + + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need validate that the */ +/* given instance exists */ +bool Notification_Class_Valid_Instance( + uint32_t object_instance) +{ + unsigned int index; + + index = Notification_Class_Instance_To_Index(object_instance); + if (index < MAX_NOTIFICATION_CLASSES) + return true; + + return false; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then count how many you have */ +unsigned Notification_Class_Count(void) +{ + return MAX_NOTIFICATION_CLASSES; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need to return the instance */ +/* that correlates to the correct index */ +uint32_t Notification_Class_Index_To_Instance(unsigned index) +{ + return index; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need to return the index */ +/* that correlates to the correct instance number */ +unsigned Notification_Class_Instance_To_Index( + uint32_t object_instance) +{ + unsigned index = MAX_NOTIFICATION_CLASSES; + + if (object_instance < MAX_NOTIFICATION_CLASSES) + index = object_instance; + + return index; +} + +bool Notification_Class_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) +{ + static char text_string[32] = ""; /* okay for single thread */ + unsigned int index; + bool status = false; + + index = Notification_Class_Instance_To_Index(object_instance); + if (index < MAX_NOTIFICATION_CLASSES) { + sprintf(text_string, "NOTIFICATION CLASS %lu", (unsigned long) index); + status = characterstring_init_ansi(object_name, text_string); + } + + return status; +} + + + +int Notification_Class_Read_Property( + BACNET_READ_PROPERTY_DATA * rpdata) +{ + NOTIFICATION_CLASS_INFO *CurrentNotify; + BACNET_CHARACTER_STRING char_string; + BACNET_OCTET_STRING octet_string; + BACNET_BIT_STRING bit_string; + uint8_t *apdu = NULL; + uint8_t u8Val; + int idx; + int apdu_len = 0; /* return value */ + + + if ((rpdata == NULL) || (rpdata->application_data == NULL) || + (rpdata->application_data_len == 0)) { + return 0; + } + + apdu = rpdata->application_data; + CurrentNotify = &NC_Info[Notification_Class_Instance_To_Index(rpdata->object_instance)]; + + switch (rpdata->object_property) + { + case PROP_OBJECT_IDENTIFIER: + apdu_len = + encode_application_object_id(&apdu[0], OBJECT_NOTIFICATION_CLASS, + rpdata->object_instance); + break; + + case PROP_OBJECT_NAME: + case PROP_DESCRIPTION: + Notification_Class_Object_Name(rpdata->object_instance, &char_string); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + + case PROP_OBJECT_TYPE: + apdu_len = + encode_application_enumerated(&apdu[0], OBJECT_NOTIFICATION_CLASS); + break; + + case PROP_NOTIFICATION_CLASS: + apdu_len += encode_application_unsigned(&apdu[0], rpdata->object_instance); + break; + + case PROP_PRIORITY: + if (rpdata->array_index == 0) + apdu_len += encode_application_unsigned(&apdu[0], 3); + else + { + if (rpdata->array_index == BACNET_ARRAY_ALL) + { + /* TO-OFFNORMAL */ + apdu_len += encode_application_unsigned(&apdu[apdu_len], + CurrentNotify->Priority[0]); + /* TO-FAULT */ + apdu_len += encode_application_unsigned(&apdu[apdu_len], + CurrentNotify->Priority[1]); + /* TO-NORMAL */ + apdu_len += encode_application_unsigned(&apdu[apdu_len], + CurrentNotify->Priority[2]); + } + else if (rpdata->array_index <= 3) + { + apdu_len += encode_application_unsigned(&apdu[apdu_len], + CurrentNotify->Priority[rpdata->array_index - 1]); + } + else + { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = -1; + } + } + break; + + case PROP_ACK_REQUIRED: + u8Val = CurrentNotify->Ack_Required; + + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, + (u8Val & TRANSITION_TO_OFFNORMAL_MASKED) ? true : false ); + bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, + (u8Val & TRANSITION_TO_FAULT_MASKED ) ? true : false ); + bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, + (u8Val & TRANSITION_TO_NORMAL_MASKED ) ? true : false ); + /* encode bitstring */ + apdu_len += encode_application_bitstring(&apdu[apdu_len], &bit_string); + break; + + case PROP_RECIPIENT_LIST: + /* encode all entry of Recipient_List */ + for (idx = 0; idx < NC_MAX_RECIPIENTS; idx++) + { + BACNET_DESTINATION *RecipientEntry; + int i = 0; + + /* get pointer of current element for Recipient_List - easier for use */ + RecipientEntry = &CurrentNotify->Recipient_List[idx]; + if (RecipientEntry->Recipient.RecipientType != RECIPIENT_TYPE_NOTINITIALIZED) + { + /* Valid Days - BACnetDaysOfWeek - [bitstring] monday-sunday */ + u8Val = 0x01; + bitstring_init(&bit_string); + + for (i = 0; i < MAX_BACNET_DAYS_OF_WEEK; i++) + { + if (RecipientEntry->ValidDays & u8Val) + bitstring_set_bit(&bit_string, i, true); + else + bitstring_set_bit(&bit_string, i, false); + u8Val <<= 1; /* next day */ + } + apdu_len += encode_application_bitstring(&apdu[apdu_len],&bit_string); + + /* From Time */ + apdu_len += encode_application_time(&apdu[apdu_len], + &RecipientEntry->FromTime); + + /* To Time */ + apdu_len += encode_application_time(&apdu[apdu_len], + &RecipientEntry->ToTime); + + /* + BACnetRecipient ::= CHOICE { + device [0] BACnetObjectIdentifier, + address [1] BACnetAddress + } */ + + /* CHOICE - device [0] BACnetObjectIdentifier */ + if(RecipientEntry->Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) + { + apdu_len += encode_context_object_id(&apdu[apdu_len], 0, OBJECT_DEVICE, + RecipientEntry->Recipient._.DeviceIdentifier); + } + /* CHOICE - address [1] BACnetAddress */ + else if (RecipientEntry->Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) + { + /* opening tag 1 */ + apdu_len += encode_opening_tag(&apdu[apdu_len], 1); + /* network-number Unsigned16, */ + apdu_len += encode_application_unsigned(&apdu[apdu_len], + RecipientEntry->Recipient._.Address.net); + + /* mac-address OCTET STRING */ + if (RecipientEntry->Recipient._.Address.net) + { + octetstring_init(&octet_string, + RecipientEntry->Recipient._.Address.adr, + RecipientEntry->Recipient._.Address.len); + } + else + { + octetstring_init(&octet_string, + RecipientEntry->Recipient._.Address.mac, + RecipientEntry->Recipient._.Address.mac_len); + } + apdu_len += encode_application_octet_string(&apdu[apdu_len], &octet_string); + + /* closing tag 1 */ + apdu_len += encode_closing_tag(&apdu[apdu_len], 1); + + } + else {;} /* shouldn't happen */ + + /* Process Identifier - Unsigned32 */ + apdu_len += encode_application_unsigned(&apdu[apdu_len], + RecipientEntry->ProcessIdentifier); + + /* Issue Confirmed Notifications - boolean */ + apdu_len += encode_application_boolean(&apdu[apdu_len], + RecipientEntry->ConfirmedNotify); + + /* Transitions - BACnet Event Transition Bits [bitstring] */ + u8Val = RecipientEntry->Transitions; + + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, + (u8Val & TRANSITION_TO_OFFNORMAL_MASKED) ? true : false ); + bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, + (u8Val & TRANSITION_TO_FAULT_MASKED ) ? true : false ); + bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, + (u8Val & TRANSITION_TO_NORMAL_MASKED ) ? true : false ); + + apdu_len += encode_application_bitstring(&apdu[apdu_len], &bit_string); + } + } + break; + + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + /* only array properties can have array options */ + if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY) && + (rpdata->array_index != BACNET_ARRAY_ALL)) + { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; + apdu_len = BACNET_STATUS_ERROR; + } + + return apdu_len; +} + + +bool Notification_Class_Write_Property( + BACNET_WRITE_PROPERTY_DATA * wp_data) +{ + NOTIFICATION_CLASS_INFO *CurrentNotify; + NOTIFICATION_CLASS_INFO TmpNotify; + BACNET_APPLICATION_DATA_VALUE value; + bool status = false; + int iOffset = 0; + uint8_t idx = 0; + int len = 0; + + + + CurrentNotify = &NC_Info[Notification_Class_Instance_To_Index(wp_data->object_instance)]; + /* decode the some of the request */ - len = bacapp_decode_application_data(wp_data->application_data, - wp_data->application_data_len, &value); - - switch (wp_data->object_property) - { - case PROP_PRIORITY: - status = - WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, - &wp_data->error_class, &wp_data->error_code); - - if (status) { - if (wp_data->array_index == 0) { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - } - else if (wp_data->array_index == BACNET_ARRAY_ALL) { + len = bacapp_decode_application_data(wp_data->application_data, + wp_data->application_data_len, &value); + + switch (wp_data->object_property) + { + case PROP_PRIORITY: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + if (wp_data->array_index == 0) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + } + else if (wp_data->array_index == BACNET_ARRAY_ALL) { /*/ FIXME: wite all array */ - } - else if (wp_data->array_index <= 3) { - CurrentNotify->Priority[wp_data->array_index - 1] = - value.type.Unsigned_Int; - } - else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - } - } - break; - - case PROP_ACK_REQUIRED: - status = - WPValidateArgType(&value, BACNET_APPLICATION_TAG_BIT_STRING, - &wp_data->error_class, &wp_data->error_code); - - if (status) { - if(value.type.Bit_String.bits_used == 3) { - CurrentNotify->Ack_Required = - value.type.Bit_String.value[0]; - } - else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } - break; - - case PROP_RECIPIENT_LIST: - - memset(&TmpNotify, 0x00, sizeof(NOTIFICATION_CLASS_INFO)); - - /* decode all packed */ - while (iOffset < wp_data->application_data_len) - { - /* Decode Valid Days */ - len = bacapp_decode_application_data( - &wp_data->application_data[iOffset], - wp_data->application_data_len, &value); - - if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - - if (value.type.Bit_String.bits_used == MAX_BACNET_DAYS_OF_WEEK) - /* store value */ - TmpNotify.Recipient_List[idx].ValidDays = value.type.Bit_String.value[0]; - else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_OTHER; - return false; - } - - iOffset += len; - /* Decode From Time */ - len = bacapp_decode_application_data( - &wp_data->application_data[iOffset], - wp_data->application_data_len, &value); - - if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_TIME)) { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - /* store value */ - TmpNotify.Recipient_List[idx].FromTime = value.type.Time; - - iOffset += len; - /* Decode To Time */ - len = bacapp_decode_application_data( - &wp_data->application_data[iOffset], - wp_data->application_data_len, &value); - - if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_TIME)) { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - /* store value */ - TmpNotify.Recipient_List[idx].ToTime = value.type.Time; - - iOffset += len; - /* context tag [0] - Device */ - if (decode_is_context_tag(&wp_data->application_data[iOffset], 0)) - { - TmpNotify.Recipient_List[idx].Recipient.RecipientType = RECIPIENT_TYPE_DEVICE; - /* Decode Network Number */ - len = bacapp_decode_context_data( - &wp_data->application_data[iOffset], - wp_data->application_data_len, &value, - PROP_RECIPIENT_LIST); - - if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_OBJECT_ID)) { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - /* store value */ - TmpNotify.Recipient_List[idx].Recipient._.DeviceIdentifier = - value.type.Object_Id.instance; - - iOffset += len; - } - /* opening tag [1] - Recipient */ - else if (decode_is_opening_tag_number(&wp_data->application_data[iOffset], 1)) - { - iOffset++; - TmpNotify.Recipient_List[idx].Recipient.RecipientType = RECIPIENT_TYPE_ADDRESS; - /* Decode Network Number */ - len = bacapp_decode_application_data( - &wp_data->application_data[iOffset], - wp_data->application_data_len, &value); - - if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT)) { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - /* store value */ - TmpNotify.Recipient_List[idx].Recipient._.Address.net = value.type.Unsigned_Int; - - iOffset += len; - /* Decode Address */ - len = bacapp_decode_application_data( - &wp_data->application_data[iOffset], - wp_data->application_data_len, &value); - - if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_OCTET_STRING)) { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - /* store value */ - if (TmpNotify.Recipient_List[idx].Recipient._.Address.net == 0) { - memcpy(TmpNotify.Recipient_List[idx].Recipient._.Address.mac, - value.type.Octet_String.value, - value.type.Octet_String.length); - TmpNotify.Recipient_List[idx].Recipient._.Address.mac_len = - value.type.Octet_String.length; - } - else { - memcpy(TmpNotify.Recipient_List[idx].Recipient._.Address.adr, - value.type.Octet_String.value, - value.type.Octet_String.length); - TmpNotify.Recipient_List[idx].Recipient._.Address.len = - value.type.Octet_String.length; - } - - iOffset += len; - /* closing tag [1] - Recipient */ - if (decode_is_closing_tag_number(&wp_data->application_data[iOffset], 1)) - iOffset++; - else { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - } - else { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - - /* Process Identifier */ - len = bacapp_decode_application_data( - &wp_data->application_data[iOffset], - wp_data->application_data_len, &value); - - if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT)) { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - /* store value */ - TmpNotify.Recipient_List[idx].ProcessIdentifier = value.type.Unsigned_Int; - - iOffset += len; - /* Issue Confirmed Notifications */ - len = bacapp_decode_application_data( - &wp_data->application_data[iOffset], - wp_data->application_data_len, &value); - - if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_BOOLEAN)) { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - /* store value */ - TmpNotify.Recipient_List[idx].ConfirmedNotify = value.type.Boolean; - - iOffset += len; - /* Transitions */ - len = bacapp_decode_application_data( - &wp_data->application_data[iOffset], - wp_data->application_data_len, &value); - - if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) { - /* Bad decode, wrong tag or following required parameter missing */ - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; - return false; - } - - if (value.type.Bit_String.bits_used == MAX_BACNET_EVENT_TRANSITION) - /* store value */ - TmpNotify.Recipient_List[idx].Transitions = value.type.Bit_String.value[0]; - else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_OTHER; - return false; - } - iOffset += len; - - /* Increasing element of list */ - if (++idx >= NC_MAX_RECIPIENTS) { - wp_data->error_class = ERROR_CLASS_RESOURCES; - wp_data->error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; - return false; - } - } - - /* Decoded all recipient list */ - /* copy elements from temporary object */ - for (idx = 0; idx < NC_MAX_RECIPIENTS; idx++) - { - BACNET_ADDRESS src = {0}; - unsigned max_apdu = 0; - int32_t DeviceID; - - CurrentNotify->Recipient_List[idx] = TmpNotify.Recipient_List[idx]; - - if (CurrentNotify->Recipient_List[idx].Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) { - /* copy Device_ID */ - DeviceID = CurrentNotify->Recipient_List[idx].Recipient._.DeviceIdentifier; - address_bind_request(DeviceID, &max_apdu, &src); - - } - else if (CurrentNotify->Recipient_List[idx].Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) { - /* copy Address */ + } + else if (wp_data->array_index <= 3) { + CurrentNotify->Priority[wp_data->array_index - 1] = + value.type.Unsigned_Int; + } + else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + } + } + break; + + case PROP_ACK_REQUIRED: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_BIT_STRING, + &wp_data->error_class, &wp_data->error_code); + + if (status) { + if(value.type.Bit_String.bits_used == 3) { + CurrentNotify->Ack_Required = + value.type.Bit_String.value[0]; + } + else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } + break; + + case PROP_RECIPIENT_LIST: + + memset(&TmpNotify, 0x00, sizeof(NOTIFICATION_CLASS_INFO)); + + /* decode all packed */ + while (iOffset < wp_data->application_data_len) + { + /* Decode Valid Days */ + len = bacapp_decode_application_data( + &wp_data->application_data[iOffset], + wp_data->application_data_len, &value); + + if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + + if (value.type.Bit_String.bits_used == MAX_BACNET_DAYS_OF_WEEK) + /* store value */ + TmpNotify.Recipient_List[idx].ValidDays = value.type.Bit_String.value[0]; + else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_OTHER; + return false; + } + + iOffset += len; + /* Decode From Time */ + len = bacapp_decode_application_data( + &wp_data->application_data[iOffset], + wp_data->application_data_len, &value); + + if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_TIME)) { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + /* store value */ + TmpNotify.Recipient_List[idx].FromTime = value.type.Time; + + iOffset += len; + /* Decode To Time */ + len = bacapp_decode_application_data( + &wp_data->application_data[iOffset], + wp_data->application_data_len, &value); + + if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_TIME)) { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + /* store value */ + TmpNotify.Recipient_List[idx].ToTime = value.type.Time; + + iOffset += len; + /* context tag [0] - Device */ + if (decode_is_context_tag(&wp_data->application_data[iOffset], 0)) + { + TmpNotify.Recipient_List[idx].Recipient.RecipientType = RECIPIENT_TYPE_DEVICE; + /* Decode Network Number */ + len = bacapp_decode_context_data( + &wp_data->application_data[iOffset], + wp_data->application_data_len, &value, + PROP_RECIPIENT_LIST); + + if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_OBJECT_ID)) { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + /* store value */ + TmpNotify.Recipient_List[idx].Recipient._.DeviceIdentifier = + value.type.Object_Id.instance; + + iOffset += len; + } + /* opening tag [1] - Recipient */ + else if (decode_is_opening_tag_number(&wp_data->application_data[iOffset], 1)) + { + iOffset++; + TmpNotify.Recipient_List[idx].Recipient.RecipientType = RECIPIENT_TYPE_ADDRESS; + /* Decode Network Number */ + len = bacapp_decode_application_data( + &wp_data->application_data[iOffset], + wp_data->application_data_len, &value); + + if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT)) { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + /* store value */ + TmpNotify.Recipient_List[idx].Recipient._.Address.net = value.type.Unsigned_Int; + + iOffset += len; + /* Decode Address */ + len = bacapp_decode_application_data( + &wp_data->application_data[iOffset], + wp_data->application_data_len, &value); + + if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_OCTET_STRING)) { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + /* store value */ + if (TmpNotify.Recipient_List[idx].Recipient._.Address.net == 0) { + memcpy(TmpNotify.Recipient_List[idx].Recipient._.Address.mac, + value.type.Octet_String.value, + value.type.Octet_String.length); + TmpNotify.Recipient_List[idx].Recipient._.Address.mac_len = + value.type.Octet_String.length; + } + else { + memcpy(TmpNotify.Recipient_List[idx].Recipient._.Address.adr, + value.type.Octet_String.value, + value.type.Octet_String.length); + TmpNotify.Recipient_List[idx].Recipient._.Address.len = + value.type.Octet_String.length; + } + + iOffset += len; + /* closing tag [1] - Recipient */ + if (decode_is_closing_tag_number(&wp_data->application_data[iOffset], 1)) + iOffset++; + else { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + } + else { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + + /* Process Identifier */ + len = bacapp_decode_application_data( + &wp_data->application_data[iOffset], + wp_data->application_data_len, &value); + + if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT)) { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + /* store value */ + TmpNotify.Recipient_List[idx].ProcessIdentifier = value.type.Unsigned_Int; + + iOffset += len; + /* Issue Confirmed Notifications */ + len = bacapp_decode_application_data( + &wp_data->application_data[iOffset], + wp_data->application_data_len, &value); + + if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_BOOLEAN)) { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + /* store value */ + TmpNotify.Recipient_List[idx].ConfirmedNotify = value.type.Boolean; + + iOffset += len; + /* Transitions */ + len = bacapp_decode_application_data( + &wp_data->application_data[iOffset], + wp_data->application_data_len, &value); + + if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) { + /* Bad decode, wrong tag or following required parameter missing */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + return false; + } + + if (value.type.Bit_String.bits_used == MAX_BACNET_EVENT_TRANSITION) + /* store value */ + TmpNotify.Recipient_List[idx].Transitions = value.type.Bit_String.value[0]; + else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_OTHER; + return false; + } + iOffset += len; + + /* Increasing element of list */ + if (++idx >= NC_MAX_RECIPIENTS) { + wp_data->error_class = ERROR_CLASS_RESOURCES; + wp_data->error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; + return false; + } + } + + /* Decoded all recipient list */ + /* copy elements from temporary object */ + for (idx = 0; idx < NC_MAX_RECIPIENTS; idx++) + { + BACNET_ADDRESS src = {0}; + unsigned max_apdu = 0; + int32_t DeviceID; + + CurrentNotify->Recipient_List[idx] = TmpNotify.Recipient_List[idx]; + + if (CurrentNotify->Recipient_List[idx].Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) { + /* copy Device_ID */ + DeviceID = CurrentNotify->Recipient_List[idx].Recipient._.DeviceIdentifier; + address_bind_request(DeviceID, &max_apdu, &src); + + } + else if (CurrentNotify->Recipient_List[idx].Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) { + /* copy Address */ /*/src = CurrentNotify->Recipient_List[idx].Recipient._.Address; */ /*/address_bind_request(BACNET_MAX_INSTANCE, &max_apdu, &src); */ - } - } - - status = true; - - break; - - default: - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; - break; - } - - return status; -} - - -static bool IsRecipientActive(BACNET_DESTINATION * pBacDest, uint8_t EventToState) -{ - BACNET_DATE_TIME DateTime; - - /* valid Transitions */ - switch (EventToState) - { - case EVENT_STATE_OFFNORMAL: - case EVENT_STATE_HIGH_LIMIT: - case EVENT_STATE_LOW_LIMIT: - if (!(pBacDest->Transitions & TRANSITION_TO_OFFNORMAL_MASKED)) - return false; - break; - - case EVENT_STATE_FAULT: - if (!(pBacDest->Transitions & TRANSITION_TO_FAULT_MASKED)) - return false; - break; - - case EVENT_STATE_NORMAL: - if (!(pBacDest->Transitions & TRANSITION_TO_NORMAL_MASKED)) - return false; - break; - - default: - return false; /* shouldn't happen */ - } - - /* get actual date and time */ - Device_getCurrentDateTime(&DateTime); - - /* valid Days */ - if (!((0x01 << (DateTime.date.wday - 1)) & pBacDest->ValidDays)) - return false; - - /* valid FromTime */ - if (datetime_compare_time(&DateTime.time, &pBacDest->FromTime) < 0) - return false; - - /* valid ToTime */ - if (datetime_compare_time(&pBacDest->ToTime, &DateTime.time) < 0) - return false; - - return true; -} - - -void Notification_Class_common_reporting_function( - BACNET_EVENT_NOTIFICATION_DATA * event_data) -{ - /* Fill the parameters common for all types of events. */ - - NOTIFICATION_CLASS_INFO *CurrentNotify; - BACNET_DESTINATION *pBacDest; - uint32_t notify_index; - uint8_t index; - - - notify_index = Notification_Class_Instance_To_Index( - event_data->notificationClass); - - if (notify_index < MAX_NOTIFICATION_CLASSES) - CurrentNotify = &NC_Info[notify_index]; - else - return; - - - /* Initiating Device Identifier */ - event_data->initiatingObjectIdentifier.type = OBJECT_DEVICE; - event_data->initiatingObjectIdentifier.instance = - Device_Object_Instance_Number(); - - /* Priority and AckRequired*/ - switch (event_data->toState) - { - case EVENT_STATE_OFFNORMAL: - event_data->priority = - CurrentNotify->Priority[EVENT_STATE_OFFNORMAL]; - event_data->ackRequired = (CurrentNotify->Ack_Required & - TRANSITION_TO_OFFNORMAL_MASKED) ? true : false; - break; - - case EVENT_STATE_FAULT: - event_data->priority = - CurrentNotify->Priority[EVENT_STATE_FAULT]; - event_data->ackRequired = (CurrentNotify->Ack_Required & - TRANSITION_TO_FAULT_MASKED) ? true : false; - break; - - case EVENT_STATE_NORMAL: - case EVENT_STATE_HIGH_LIMIT: - case EVENT_STATE_LOW_LIMIT: - event_data->priority = - CurrentNotify->Priority[EVENT_STATE_NORMAL]; - event_data->ackRequired = (CurrentNotify->Ack_Required & - TRANSITION_TO_NORMAL) ? true : false; - break; - + } + } + + status = true; + + break; + + default: + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + break; + } + + return status; +} + + +static bool IsRecipientActive(BACNET_DESTINATION * pBacDest, uint8_t EventToState) +{ + BACNET_DATE_TIME DateTime; + + /* valid Transitions */ + switch (EventToState) + { + case EVENT_STATE_OFFNORMAL: + case EVENT_STATE_HIGH_LIMIT: + case EVENT_STATE_LOW_LIMIT: + if (!(pBacDest->Transitions & TRANSITION_TO_OFFNORMAL_MASKED)) + return false; + break; + + case EVENT_STATE_FAULT: + if (!(pBacDest->Transitions & TRANSITION_TO_FAULT_MASKED)) + return false; + break; + + case EVENT_STATE_NORMAL: + if (!(pBacDest->Transitions & TRANSITION_TO_NORMAL_MASKED)) + return false; + break; + + default: + return false; /* shouldn't happen */ + } + + /* get actual date and time */ + Device_getCurrentDateTime(&DateTime); + + /* valid Days */ + if (!((0x01 << (DateTime.date.wday - 1)) & pBacDest->ValidDays)) + return false; + + /* valid FromTime */ + if (datetime_compare_time(&DateTime.time, &pBacDest->FromTime) < 0) + return false; + + /* valid ToTime */ + if (datetime_compare_time(&pBacDest->ToTime, &DateTime.time) < 0) + return false; + + return true; +} + + +void Notification_Class_common_reporting_function( + BACNET_EVENT_NOTIFICATION_DATA * event_data) +{ + /* Fill the parameters common for all types of events. */ + + NOTIFICATION_CLASS_INFO *CurrentNotify; + BACNET_DESTINATION *pBacDest; + uint32_t notify_index; + uint8_t index; + + + notify_index = Notification_Class_Instance_To_Index( + event_data->notificationClass); + + if (notify_index < MAX_NOTIFICATION_CLASSES) + CurrentNotify = &NC_Info[notify_index]; + else + return; + + + /* Initiating Device Identifier */ + event_data->initiatingObjectIdentifier.type = OBJECT_DEVICE; + event_data->initiatingObjectIdentifier.instance = + Device_Object_Instance_Number(); + + /* Priority and AckRequired*/ + switch (event_data->toState) + { + case EVENT_STATE_OFFNORMAL: + event_data->priority = + CurrentNotify->Priority[EVENT_STATE_OFFNORMAL]; + event_data->ackRequired = (CurrentNotify->Ack_Required & + TRANSITION_TO_OFFNORMAL_MASKED) ? true : false; + break; + + case EVENT_STATE_FAULT: + event_data->priority = + CurrentNotify->Priority[EVENT_STATE_FAULT]; + event_data->ackRequired = (CurrentNotify->Ack_Required & + TRANSITION_TO_FAULT_MASKED) ? true : false; + break; + + case EVENT_STATE_NORMAL: + case EVENT_STATE_HIGH_LIMIT: + case EVENT_STATE_LOW_LIMIT: + event_data->priority = + CurrentNotify->Priority[EVENT_STATE_NORMAL]; + event_data->ackRequired = (CurrentNotify->Ack_Required & + TRANSITION_TO_NORMAL) ? true : false; + break; + default: /* shouldn't happen */ - break; - } - - /* send notifications for active recipients */ - /* pointer to first recipient */ - pBacDest = &CurrentNotify->Recipient_List[0]; - for (index = 0; index < NC_MAX_RECIPIENTS; index++, pBacDest++) - { - /* check if recipient is defined */ - if (pBacDest->Recipient.RecipientType == RECIPIENT_TYPE_NOTINITIALIZED) - break; /* recipient doesn't defined - end of list */ - - if (IsRecipientActive(pBacDest, event_data->toState) == true) - { - BACNET_ADDRESS dest; - uint32_t device_id; - unsigned max_apdu; - - /* Process Identifier */ - event_data->processIdentifier = pBacDest->ProcessIdentifier; - - /* send notification */ - if (pBacDest->Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) { - /* send notification to the specified device */ - device_id = pBacDest->Recipient._.DeviceIdentifier; - - if (pBacDest->ConfirmedNotify == true) - Send_CEvent_Notify(device_id, event_data); - else if (address_get_by_device(device_id, &max_apdu, &dest)) - Send_UEvent_Notify(Handler_Transmit_Buffer, event_data, &dest); - } - else if (pBacDest->Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) { - /* send notification to the address indicated */ - if (pBacDest->ConfirmedNotify == true) { - if (address_get_device_id(&dest, &device_id)) - Send_CEvent_Notify(device_id, event_data); - } - else { - dest = pBacDest->Recipient._.Address; - Send_UEvent_Notify(Handler_Transmit_Buffer, event_data, &dest); - } - } - } - } -} - -/* This function tries to find the addresses of the defined devices. */ -/* It should be called periodically (example once per minute). */ -void Notification_Class_find_recipient(void) -{ - NOTIFICATION_CLASS_INFO *CurrentNotify; - BACNET_DESTINATION *pBacDest; - BACNET_ADDRESS src = {0}; - unsigned max_apdu = 0; - uint32_t notify_index; - uint32_t DeviceID; - uint8_t idx; - - - for (notify_index = 0; notify_index < MAX_NOTIFICATION_CLASSES; notify_index++) - { - /* pointer to current notification */ - CurrentNotify = &NC_Info[Notification_Class_Instance_To_Index(notify_index)]; - /* pointer to first recipient */ - pBacDest = &CurrentNotify->Recipient_List[0]; - for (idx = 0; idx < NC_MAX_RECIPIENTS; idx++, pBacDest++) - { - if (CurrentNotify->Recipient_List[idx].Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) { - /* Device ID */ - DeviceID = CurrentNotify->Recipient_List[idx].Recipient._.DeviceIdentifier; - /* Send who_ is request only when address of device is unknown. */ - if(!address_bind_request(DeviceID, &max_apdu, &src)) - Send_WhoIs(DeviceID, DeviceID); - } - else if(CurrentNotify->Recipient_List[idx].Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) { - - } - } - } -} -#endif /* defined(INTRINSIC_REPORTING) */ + break; + } + + /* send notifications for active recipients */ + /* pointer to first recipient */ + pBacDest = &CurrentNotify->Recipient_List[0]; + for (index = 0; index < NC_MAX_RECIPIENTS; index++, pBacDest++) + { + /* check if recipient is defined */ + if (pBacDest->Recipient.RecipientType == RECIPIENT_TYPE_NOTINITIALIZED) + break; /* recipient doesn't defined - end of list */ + + if (IsRecipientActive(pBacDest, event_data->toState) == true) + { + BACNET_ADDRESS dest; + uint32_t device_id; + unsigned max_apdu; + + /* Process Identifier */ + event_data->processIdentifier = pBacDest->ProcessIdentifier; + + /* send notification */ + if (pBacDest->Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) { + /* send notification to the specified device */ + device_id = pBacDest->Recipient._.DeviceIdentifier; + + if (pBacDest->ConfirmedNotify == true) + Send_CEvent_Notify(device_id, event_data); + else if (address_get_by_device(device_id, &max_apdu, &dest)) + Send_UEvent_Notify(Handler_Transmit_Buffer, event_data, &dest); + } + else if (pBacDest->Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) { + /* send notification to the address indicated */ + if (pBacDest->ConfirmedNotify == true) { + if (address_get_device_id(&dest, &device_id)) + Send_CEvent_Notify(device_id, event_data); + } + else { + dest = pBacDest->Recipient._.Address; + Send_UEvent_Notify(Handler_Transmit_Buffer, event_data, &dest); + } + } + } + } +} + +/* This function tries to find the addresses of the defined devices. */ +/* It should be called periodically (example once per minute). */ +void Notification_Class_find_recipient(void) +{ + NOTIFICATION_CLASS_INFO *CurrentNotify; + BACNET_DESTINATION *pBacDest; + BACNET_ADDRESS src = {0}; + unsigned max_apdu = 0; + uint32_t notify_index; + uint32_t DeviceID; + uint8_t idx; + + + for (notify_index = 0; notify_index < MAX_NOTIFICATION_CLASSES; notify_index++) + { + /* pointer to current notification */ + CurrentNotify = &NC_Info[Notification_Class_Instance_To_Index(notify_index)]; + /* pointer to first recipient */ + pBacDest = &CurrentNotify->Recipient_List[0]; + for (idx = 0; idx < NC_MAX_RECIPIENTS; idx++, pBacDest++) + { + if (CurrentNotify->Recipient_List[idx].Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) { + /* Device ID */ + DeviceID = CurrentNotify->Recipient_List[idx].Recipient._.DeviceIdentifier; + /* Send who_ is request only when address of device is unknown. */ + if(!address_bind_request(DeviceID, &max_apdu, &src)) + Send_WhoIs(DeviceID, DeviceID); + } + else if(CurrentNotify->Recipient_List[idx].Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) { + + } + } + } +} +#endif /* defined(INTRINSIC_REPORTING) */ diff --git a/bacnet-stack/demo/object/nc.h b/bacnet-stack/demo/object/nc.h index 0dcc97d3..6ad6f86b 100644 --- a/bacnet-stack/demo/object/nc.h +++ b/bacnet-stack/demo/object/nc.h @@ -121,4 +121,4 @@ typedef struct Notification_Class_info { Notification_Class_Write_Property, Notification_Class_Property_Lists, \ NULL, NULL, NULL -#endif /* NC_H */ +#endif /* NC_H */ diff --git a/bacnet-stack/demo/server/main.c b/bacnet-stack/demo/server/main.c index 97fb0620..355d04ab 100644 --- a/bacnet-stack/demo/server/main.c +++ b/bacnet-stack/demo/server/main.c @@ -206,7 +206,7 @@ int main( tsm_timer_milliseconds(elapsed_milliseconds); trend_log_timer(elapsed_seconds); #if defined(INTRINSIC_REPORTING) - Device_local_reporting(elapsed_seconds * 1000); + Device_local_reporting(); #endif } /* scan cache address */