diff --git a/demo/object/ai.c b/demo/object/ai.c index df7a75e..e956bca 100644 --- a/demo/object/ai.c +++ b/demo/object/ai.c @@ -1,7 +1,8 @@ /************************************************************************** * -* Copyright (C) 2005 Steve Karg +* Copyright (C) 2006 Steve Karg * Copyright (C) 2011 Krzysztof Malorny +* Copyright (C) 2013 Patrick Grimm * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -24,32 +25,44 @@ * *********************************************************************/ -/* Analog Input Objects customize for your use */ +/* Analog Input Objects - customize for your use */ #include #include #include +#include +#include #include "bacdef.h" #include "bacdcode.h" #include "bacenum.h" +#include "bacapp.h" #include "bactext.h" #include "config.h" /* the custom stuff */ #include "device.h" #include "handlers.h" -#include "timestamp.h" #include "ai.h" +#include "ucix.h" - +/* number of demo objects */ #ifndef MAX_ANALOG_INPUTS -#define MAX_ANALOG_INPUTS 4 +#define MAX_ANALOG_INPUTS 65535 #endif +unsigned max_analog_inputs_int = 0; +/* When all the priorities are level null, the present value returns */ +/* the Relinquish Default value */ +#define ANALOG_RELINQUISH_DEFAULT 0 + +/* we choose to have a NULL level in our system represented by */ +/* a particular value. When the priorities are not in use, they */ +/* will be relinquished (i.e. set to the NULL level). */ +#define ANALOG_LEVEL_NULL 255 ANALOG_INPUT_DESCR AI_Descr[MAX_ANALOG_INPUTS]; /* These three arrays are used by the ReadPropertyMultiple handler */ -static const int Properties_Required[] = { +static const int Analog_Input_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE, @@ -61,9 +74,10 @@ static const int Properties_Required[] = { -1 }; -static const int Properties_Optional[] = { +static const int Analog_Input_Properties_Optional[] = { PROP_DESCRIPTION, - PROP_RELIABILITY, + PROP_PRIORITY_ARRAY, + PROP_RELINQUISH_DEFAULT, #if defined(INTRINSIC_REPORTING) PROP_TIME_DELAY, PROP_NOTIFICATION_CLASS, @@ -76,88 +90,317 @@ static const int Properties_Optional[] = { PROP_NOTIFY_TYPE, PROP_EVENT_TIME_STAMPS, #endif + PROP_RELIABILITY, -1 }; -static const int Properties_Proprietary[] = { - 9997, - 9998, - 9999, +static const int Analog_Input_Properties_Proprietary[] = { -1 }; +struct uci_context *ctx; + void Analog_Input_Property_Lists( const int **pRequired, const int **pOptional, const int **pProprietary) { if (pRequired) - *pRequired = Properties_Required; + *pRequired = Analog_Input_Properties_Required; if (pOptional) - *pOptional = Properties_Optional; + *pOptional = Analog_Input_Properties_Optional; if (pProprietary) - *pProprietary = Properties_Proprietary; + *pProprietary = Analog_Input_Properties_Proprietary; return; } +void Analog_Input_Load_UCI_List(const char *sec_idx, + struct ai_inst_itr_ctx *itr) +{ + ai_inst_tuple_t *t = malloc(sizeof(ai_inst_tuple_t)); + bool disable; + disable = ucix_get_option_int(itr->ctx, itr->section, sec_idx, + "disable", 0); + if (strcmp(sec_idx,"default") == 0) + return; + if (disable) + return; + if( (t = (ai_inst_tuple_t *)malloc(sizeof(ai_inst_tuple_t))) != NULL ) { + strncpy(t->idx, sec_idx, sizeof(t->idx)); + t->next = itr->list; + itr->list = t; + } + return; +} + void Analog_Input_Init( void) { - unsigned i; -#if defined(INTRINSIC_REPORTING) - unsigned j; -#endif + unsigned i, j; + static bool initialized = false; + char name[64]; + const char *uciname; + int ucidisable; + const char *ucivalue; + int Out_Of_Service; + char description[64]; + const char *ucidescription; + const char *ucidescription_default; + const char *idx_c; + char idx_cc[64]; + int uciunit = 0; + int uciunit_default = 0; + const char *ucivalue_default; + int ucinc_default; + int ucinc; + int ucievent_default; + int ucievent; + int ucitime_delay_default; + int ucitime_delay; + int ucilimit_default; + int ucilimit; + char high_limit[64]; + const char *ucihigh_limit_default; + const char *ucihigh_limit; + char low_limit[64]; + const char *ucilow_limit_default; + const char *ucilow_limit; + char dead_limit[64]; + const char *ucidead_limit_default; + const char *ucidead_limit; + char cov_increment[64]; + const char *ucicov_increment; + const char *ucicov_increment_default; + const char *sec = "bacnet_ai"; + + char *section; + char *type; + struct ai_inst_itr_ctx itr_m; + section = "bacnet_ai"; + +#if PRINT_ENABLED + fprintf(stderr, "Analog_Input_Init\n"); +#endif + if (!initialized) { + initialized = true; + ctx = ucix_init(sec); +#if PRINT_ENABLED + if(!ctx) + fprintf(stderr, "Failed to load config file bacnet_ai\n"); +#endif + type = "ai"; + ai_inst_tuple_t *cur = malloc(sizeof (ai_inst_tuple_t)); + itr_m.list = NULL; + itr_m.section = section; + itr_m.ctx = ctx; + ucix_for_each_section_type(ctx, section, type, + (void *)Analog_Input_Load_UCI_List, &itr_m); + + ucidescription_default = ucix_get_option(ctx, sec, "default", + "description"); + uciunit_default = ucix_get_option_int(ctx, sec, "default", + "si_unit", 0); + ucivalue_default = ucix_get_option(ctx, sec, "default", + "value"); + ucinc_default = ucix_get_option_int(ctx, sec, "default", + "nc", -1); + ucievent_default = ucix_get_option_int(ctx, sec, "default", + "event", -1); + ucitime_delay_default = ucix_get_option_int(ctx, sec, "default", + "time_delay", -1); + ucilimit_default = ucix_get_option_int(ctx, sec, "default", + "limit", -1); + ucihigh_limit_default = ucix_get_option(ctx, sec, "default", + "high_limit"); + ucilow_limit_default = ucix_get_option(ctx, sec, "default", + "low_limit"); + ucidead_limit_default = ucix_get_option(ctx, sec, "default", + "dead_limit"); + ucicov_increment_default = ucix_get_option(ctx, sec, "default", + "cov_increment"); + i = 0; + for( cur = itr_m.list; cur; cur = cur->next ) { + strncpy(idx_cc, cur->idx, sizeof(idx_cc)); + idx_c = idx_cc; + uciname = ucix_get_option(ctx, "bacnet_ai", idx_c, "name"); + ucidisable = ucix_get_option_int(ctx, "bacnet_ai", idx_c, + "disable", 0); + if ((uciname != 0) && (ucidisable == 0)) { + memset(&AI_Descr[i], 0x00, sizeof(ANALOG_INPUT_DESCR)); + /* initialize all the analog input priority arrays to NULL */ + for (j = 0; j < BACNET_MAX_PRIORITY; j++) { + AI_Descr[i].Priority_Array[j] = ANALOG_LEVEL_NULL; + } + AI_Descr[i].Instance=atoi(idx_cc); + AI_Descr[i].Disable=false; + sprintf(name, "%s", uciname); + ucix_string_copy(AI_Descr[i].Object_Name, + sizeof(AI_Descr[i].Object_Name), name); + ucidescription = ucix_get_option(ctx, "bacnet_ai", idx_c, + "description"); + if (ucidescription != 0) { + sprintf(description, "%s", ucidescription); + } else if (ucidescription_default != 0) { + sprintf(description, "%s %lu", ucidescription_default, + (unsigned long) i); + } else { + sprintf(description, "AI%lu no uci section configured", + (unsigned long) i); + } + ucix_string_copy(AI_Descr[i].Object_Description, + sizeof(AI_Descr[i].Object_Description), description); + uciunit = ucix_get_option_int(ctx, "bacnet_ai", idx_c, + "si_unit", 0); + if (uciunit != 0) { + AI_Descr[i].Units = uciunit; + } else if (uciunit_default != 0) { + AI_Descr[i].Units = uciunit_default; + } else { + AI_Descr[i].Units = UNITS_PERCENT; + } + Out_Of_Service = ucix_get_option_int(ctx, "bacnet_ai", idx_c, + "Out_Of_Service", 1); + if (Out_Of_Service == 0) { + AI_Descr[i].Reliability = RELIABILITY_NO_FAULT_DETECTED; + AI_Descr[i].Out_Of_Service = 0; + } else { + AI_Descr[i].Reliability = RELIABILITY_COMMUNICATION_FAILURE; + AI_Descr[i].Out_Of_Service = 1; + } + + ucivalue = ucix_get_option(ctx, "bacnet_ai", idx_c, + "value"); + if (ucivalue == NULL) { + if (ucivalue_default == NULL) { + ucivalue = 0; + } else { + ucivalue = ucivalue_default; + AI_Descr[i].Reliability = + RELIABILITY_COMMUNICATION_FAILURE; + } + } + AI_Descr[i].Priority_Array[15] = strtof(ucivalue, + (char **) NULL); + + AI_Descr[i].Relinquish_Default = 0; //TODO read uci + + ucicov_increment = ucix_get_option(ctx, "bacnet_ai", idx_c, + "cov_increment"); + if (ucicov_increment != 0) { + sprintf(cov_increment, "%s", ucicov_increment); + } else { + if (ucicov_increment_default != 0) { + sprintf(cov_increment, "%s", ucicov_increment_default); + } else { + sprintf(cov_increment, "%s", "0"); + } + } + AI_Descr[i].COV_Increment = strtof(cov_increment, + (char **) NULL); - 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 - and set Acked_transitions */ - for (j = 0; j < MAX_BACNET_EVENT_TRANSITION; j++) { - datetime_wildcard_set(&AI_Descr[i].Event_Time_Stamps[j]); - AI_Descr[i].Acked_Transitions[j].bIsAcked = true; + ucinc = ucix_get_option_int(ctx, "bacnet_ai", idx_c, + "nc", ucinc_default); + ucievent = ucix_get_option_int(ctx, "bacnet_ai", idx_c, + "event", ucievent_default); + ucitime_delay = ucix_get_option_int(ctx, "bacnet_ai", idx_c, + "time_delay", ucitime_delay_default); + ucilimit = ucix_get_option_int(ctx, "bacnet_ai", idx_c, + "limit", ucilimit_default); + ucihigh_limit = ucix_get_option(ctx, "bacnet_ai", idx_c, + "high_limit"); + if (ucihigh_limit != 0) { + sprintf(high_limit, "%s", ucihigh_limit); + } else { + if (ucihigh_limit_default != 0) { + sprintf(high_limit, "%s", ucihigh_limit_default); + } else { + sprintf(high_limit, "%s", "0"); + } + } + ucilow_limit = ucix_get_option(ctx, "bacnet_ai", idx_c, + "low_limit"); + if (ucilow_limit != 0) { + sprintf(low_limit, "%s", ucilow_limit); + } else { + if (ucilow_limit_default != 0) { + sprintf(low_limit, "%s", ucilow_limit_default); + } else { + sprintf(low_limit, "%s", "0"); + } + } + ucidead_limit = ucix_get_option(ctx, "bacnet_ai", idx_c, + "dead_limit"); + if (ucidead_limit != 0) { + sprintf(dead_limit, "%s", ucidead_limit); + } else { + if (ucidead_limit_default != 0) { + sprintf(dead_limit, "%s", ucidead_limit_default); + } else { + sprintf(dead_limit, "%s", "0"); + } + } + AI_Descr[i].Event_State = EVENT_STATE_NORMAL; + /* notification class not connected */ + if (ucinc > -1) AI_Descr[i].Notification_Class = ucinc; + else AI_Descr[i].Notification_Class = 0; + if (ucievent > -1) AI_Descr[i].Event_Enable = ucievent; + else AI_Descr[i].Event_Enable = 0; + if (ucitime_delay > -1) AI_Descr[i].Time_Delay = ucitime_delay; + else AI_Descr[i].Time_Delay = 0; + if (ucilimit > -1) AI_Descr[i].Limit_Enable = ucilimit; + else AI_Descr[i].Limit_Enable = 0; + AI_Descr[i].High_Limit = strtof(high_limit, (char **) NULL); + AI_Descr[i].Low_Limit = strtof(low_limit, (char **) NULL); + AI_Descr[i].Deadband = strtof(dead_limit, (char **) NULL); + + /* initialize Event time stamps using wildcards + and set Acked_transitions */ + for (j = 0; j < MAX_BACNET_EVENT_TRANSITION; j++) { + 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); + /* Set handler for GetAlarmSummary Service */ + handler_get_alarm_summary_set(OBJECT_ANALOG_INPUT, + Analog_Input_Alarm_Summary); +#endif + i++; + max_analog_inputs_int = i; + } } - - /* 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); - /* Set handler for GetAlarmSummary Service */ - handler_get_alarm_summary_set(OBJECT_ANALOG_INPUT, - Analog_Input_Alarm_Summary); +#if PRINT_ENABLED + fprintf(stderr, "max_analog_inputs %i\n", max_analog_inputs_int); #endif + if(ctx) + ucix_cleanup(ctx); } + return; } /* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need validate that the */ -/* given instance exists */ -bool Analog_Input_Valid_Instance( +/* more complex, and then you need to return the index */ +/* that correlates to the correct instance number */ +unsigned Analog_Input_Instance_To_Index( uint32_t object_instance) { - unsigned int index; - - index = Analog_Input_Instance_To_Index(object_instance); - if (index < MAX_ANALOG_INPUTS) - return true; - - return false; -} - -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then count how many you have */ -unsigned Analog_Input_Count( - void) -{ + ANALOG_INPUT_DESCR *CurrentAI; + int index,instance,i; + index = max_analog_inputs_int; + for (i = 0; i < index; i++) { + CurrentAI = &AI_Descr[i]; + instance = CurrentAI->Instance; + if (CurrentAI->Instance == object_instance) { + return i; + } + } return MAX_ANALOG_INPUTS; } @@ -167,80 +410,443 @@ unsigned Analog_Input_Count( uint32_t Analog_Input_Index_To_Instance( unsigned index) { - return index; + ANALOG_INPUT_DESCR *CurrentAI; + uint32_t instance; + CurrentAI = &AI_Descr[index]; + instance = CurrentAI->Instance; + return instance; } /* 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 Analog_Input_Instance_To_Index( +/* more complex, and then count how many you have */ +unsigned Analog_Input_Count( + void) +{ + return max_analog_inputs_int; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need validate that the */ +/* given instance exists */ +bool Analog_Input_Valid_Instance( uint32_t object_instance) { - unsigned index = MAX_ANALOG_INPUTS; + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* offset from instance lookup */ + index = Analog_Input_Instance_To_Index(object_instance); + if (index == MAX_ANALOG_INPUTS) { +#if PRINT_ENABLED + fprintf(stderr, "Analog_Input_Valid_Instance %i invalid\n",object_instance); +#endif + return false; + } + CurrentAI = &AI_Descr[index]; + if (CurrentAI->Disable == false) + return true; - if (object_instance < MAX_ANALOG_INPUTS) - index = object_instance; - - return index; + return false; } -float Analog_Input_Present_Value( +bool Analog_Input_Change_Of_Value( uint32_t object_instance) { - float value = 0.0; - unsigned int index; - - index = Analog_Input_Instance_To_Index(object_instance); - if (index < MAX_ANALOG_INPUTS) { - value = AI_Descr[index].Present_Value; - } - - return value; -} - -void Analog_Input_Present_Value_Set( - uint32_t object_instance, - float value) -{ - unsigned int index; - - index = Analog_Input_Instance_To_Index(object_instance); - if (index < MAX_ANALOG_INPUTS) { - AI_Descr[index].Present_Value = value; - } -} - -bool Analog_Input_Object_Name( - uint32_t object_instance, - BACNET_CHARACTER_STRING * object_name) -{ - static char text_string[32] = ""; /* okay for single thread */ - unsigned int index; + ANALOG_INPUT_DESCR *CurrentAI; bool status = false; + unsigned index = 0; - index = Analog_Input_Instance_To_Index(object_instance); - if (index < MAX_ANALOG_INPUTS) { - sprintf(text_string, "ANALOG INPUT %lu", (unsigned long) index); - status = characterstring_init_ansi(object_name, text_string); + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + status = CurrentAI->Change_Of_Value; } return status; } -/* return apdu length, or BACNET_STATUS_ERROR on error */ -/* assumption - object has already exists */ +void Analog_Input_Change_Of_Value_Clear( + uint32_t object_instance) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + CurrentAI->Change_Of_Value = false; + } + + return; +} + + +/* returns true if value has changed */ +bool Analog_Input_Encode_Value_List( + uint32_t object_instance, + BACNET_PROPERTY_VALUE * value_list) +{ + bool status = false; + + if (value_list) { + value_list->propertyIdentifier = PROP_PRESENT_VALUE; + value_list->propertyArrayIndex = BACNET_ARRAY_ALL; + value_list->value.context_specific = false; + value_list->value.tag = BACNET_APPLICATION_TAG_ENUMERATED; + value_list->value.type.Enumerated = + Analog_Input_Present_Value(object_instance); + value_list->priority = BACNET_NO_PRIORITY; + value_list = value_list->next; + } + if (value_list) { + value_list->propertyIdentifier = PROP_STATUS_FLAGS; + value_list->propertyArrayIndex = BACNET_ARRAY_ALL; + value_list->value.context_specific = false; + value_list->value.tag = BACNET_APPLICATION_TAG_BIT_STRING; + bitstring_init(&value_list->value.type.Bit_String); + bitstring_set_bit(&value_list->value.type.Bit_String, + STATUS_FLAG_IN_ALARM, false); + bitstring_set_bit(&value_list->value.type.Bit_String, + STATUS_FLAG_FAULT, false); + bitstring_set_bit(&value_list->value.type.Bit_String, + STATUS_FLAG_OVERRIDDEN, false); + if (Analog_Input_Out_Of_Service(object_instance)) { + bitstring_set_bit(&value_list->value.type.Bit_String, + STATUS_FLAG_OUT_OF_SERVICE, true); + } else { + bitstring_set_bit(&value_list->value.type.Bit_String, + STATUS_FLAG_OUT_OF_SERVICE, false); + } + value_list->priority = BACNET_NO_PRIORITY; + } + status = Analog_Input_Change_Of_Value(object_instance); + + return status; +} + +float Analog_Input_Present_Value( + uint32_t object_instance) +{ + ANALOG_INPUT_DESCR *CurrentAI; + float value = ANALOG_RELINQUISH_DEFAULT; + unsigned index = 0; /* offset from instance lookup */ + unsigned i = 0; + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + /* When all the priorities are level null, the present value returns */ + /* the Relinquish Default value */ + value = CurrentAI->Relinquish_Default; + for (i = 0; i < BACNET_MAX_PRIORITY; i++) { + if (CurrentAI->Priority_Array[i] != ANALOG_LEVEL_NULL) { + value = CurrentAI->Priority_Array[i]; + break; + } + } + } + + return value; +} + +unsigned Analog_Input_Present_Value_Priority( + uint32_t object_instance) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* instance to index conversion */ + unsigned i = 0; /* loop counter */ + unsigned priority = 0; /* return value */ + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + for (i = 0; i < BACNET_MAX_PRIORITY; i++) { + if (CurrentAI->Priority_Array[priority] != ANALOG_LEVEL_NULL) { + priority = i + 1; + break; + } + } + } + + return priority; +} + +bool Analog_Input_Present_Value_Set( + uint32_t object_instance, + float value, + uint8_t priority) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* offset from instance lookup */ + bool status = false; + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + if (priority && (priority <= BACNET_MAX_PRIORITY) && + (priority != 6 /* reserved */ ) ) { + //CurrentAI->Present_Value = value; + CurrentAI->Priority_Array[priority - 1] = value; + /* Note: you could set the physical output here to the next + highest priority, or to the relinquish default if no + priorities are set. + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the + main loop (i.e. check out of service before changing output) */ + if (priority == 8) { + CurrentAI->Priority_Array[15] = value; + } + status = true; + } + } + return status; +} + +bool Analog_Input_Out_Of_Service( + uint32_t object_instance) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* offset from instance lookup */ + bool value = false; + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + value = CurrentAI->Out_Of_Service; + } + + return value; +} + +void Analog_Input_Out_Of_Service_Set( + uint32_t object_instance, + bool value) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + CurrentAI->Out_Of_Service = value; + } + + return; +} + +void Analog_Input_Reliability_Set( + uint32_t object_instance, + uint8_t value) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + CurrentAI->Reliability = value; + } + + return; +} + +uint8_t Analog_Input_Reliability( + uint32_t object_instance) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* offset from instance lookup */ + uint8_t value = 0; + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + value = CurrentAI->Reliability; + } + + return value; +} + +static char *Analog_Input_Description( + uint32_t object_instance) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* offset from instance lookup */ + char *pName = NULL; /* return value */ + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + pName = CurrentAI->Object_Description; + } + + return pName; +} + +bool Analog_Input_Description_Set( + uint32_t object_instance, + char *new_name) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* offset from instance lookup */ + size_t i = 0; /* loop counter */ + bool status = false; /* return value */ + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + status = true; + if (new_name) { + for (i = 0; i < sizeof(CurrentAI->Object_Description); i++) { + CurrentAI->Object_Description[i] = new_name[i]; + if (new_name[i] == 0) { + break; + } + } + } else { + for (i = 0; i < sizeof(CurrentAI->Object_Description); i++) { + CurrentAI->Object_Description[i] = 0; + } + } + } + + return status; +} + +static bool Analog_Input_Description_Write( + uint32_t object_instance, + BACNET_CHARACTER_STRING *char_string, + BACNET_ERROR_CLASS *error_class, + BACNET_ERROR_CODE *error_code) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* offset from instance lookup */ + size_t length = 0; + uint8_t encoding = 0; + bool status = false; /* return value */ + const char *idx_c; + char idx_cc[64]; + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + length = characterstring_length(char_string); + if (length <= sizeof(CurrentAI->Object_Description)) { + encoding = characterstring_encoding(char_string); + if (encoding == CHARACTER_UTF8) { + status = characterstring_ansi_copy( + CurrentAI->Object_Description, + sizeof(CurrentAI->Object_Description), + char_string); + if (!status) { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } else { + sprintf(idx_cc,"%d",CurrentAI->Instance); + idx_c = idx_cc; + if(ctx) { + ucix_add_option(ctx, "bacnet_ai", idx_c, + "description", char_string->value); +#if PRINT_ENABLED + } else { + fprintf(stderr, + "Failed to open config file bacnet_ai\n"); +#endif + } + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; + } + } + + return status; +} + +/* note: the object name must be unique within this device */ +bool Analog_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING * object_name) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* offset from instance lookup */ + bool status = false; + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + status = characterstring_init_ansi(object_name, CurrentAI->Object_Name); + } + + return status; +} + +static bool Analog_Input_Object_Name_Write( + uint32_t object_instance, + BACNET_CHARACTER_STRING *char_string, + BACNET_ERROR_CLASS *error_class, + BACNET_ERROR_CODE *error_code) +{ + ANALOG_INPUT_DESCR *CurrentAI; + unsigned index = 0; /* offset from instance lookup */ + size_t length = 0; + uint8_t encoding = 0; + bool status = false; /* return value */ + const char *idx_c; + char idx_cc[64]; + + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + length = characterstring_length(char_string); + if (length <= sizeof(CurrentAI->Object_Name)) { + encoding = characterstring_encoding(char_string); + if (encoding == CHARACTER_UTF8) { + status = characterstring_ansi_copy( + CurrentAI->Object_Name, + sizeof(CurrentAI->Object_Name), + char_string); + if (!status) { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } else { + sprintf(idx_cc,"%d",CurrentAI->Instance); + idx_c = idx_cc; + if(ctx) { + ucix_add_option(ctx, "bacnet_ai", idx_c, + "name", char_string->value); +#if PRINT_ENABLED + } else { + fprintf(stderr, + "Failed to open config file bacnet_ai\n"); +#endif + } + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; + } + } + + return status; +} + +/* return apdu len, or BACNET_STATUS_ERROR on error */ int Analog_Input_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { + ANALOG_INPUT_DESCR *CurrentAI; + 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; -#if defined(INTRINSIC_REPORTING) + float present_value = 0; + unsigned index = 0; unsigned i = 0; - int len = 0; -#endif uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || @@ -248,14 +854,15 @@ int Analog_Input_Read_Property( return 0; } - object_index = Analog_Input_Instance_To_Index(rpdata->object_instance); - if (object_index < MAX_ANALOG_INPUTS) - CurrentAI = &AI_Descr[object_index]; - else + apdu = rpdata->application_data; + + if (Analog_Input_Valid_Instance(rpdata->object_instance)) { + index = Analog_Input_Instance_To_Index(rpdata->object_instance); + CurrentAI = &AI_Descr[index]; + } else return BACNET_STATUS_ERROR; - apdu = rpdata->application_data; - switch ((int) rpdata->object_property) { + switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT, @@ -263,21 +870,26 @@ int Analog_Input_Read_Property( 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_DESCRIPTION: + characterstring_init_ansi(&char_string, + Analog_Input_Description(rpdata->object_instance)); + 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)); + present_value = Analog_Input_Present_Value(rpdata->object_instance); + apdu_len = encode_application_real(&apdu[0], present_value); break; case PROP_STATUS_FLAGS: @@ -290,8 +902,13 @@ int Analog_Input_Read_Property( #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, - CurrentAI->Out_Of_Service); + if (Analog_Input_Out_Of_Service(rpdata->object_instance)) { + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, + true); + } else { + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, + false); + } apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; @@ -307,16 +924,20 @@ int Analog_Input_Read_Property( #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], - CurrentAI->Out_Of_Service); + Analog_Input_Out_Of_Service(rpdata->object_instance)); + break; + + case PROP_RELIABILITY: + apdu_len = encode_application_enumerated(&apdu[0], + CurrentAI->Reliability); + break; + + case PROP_COV_INCREMENT: + apdu_len = encode_application_real(&apdu[0], + CurrentAI->COV_Increment); break; case PROP_UNITS: @@ -324,6 +945,58 @@ int Analog_Input_Read_Property( encode_application_enumerated(&apdu[0], CurrentAI->Units); break; + case PROP_PRIORITY_ARRAY: + /* Array element zero is the number of elements in the array */ + if (rpdata->array_index == 0) + apdu_len = + encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); + /* 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 < BACNET_MAX_PRIORITY; i++) { + /* FIXME: check if we have room before adding it to APDU */ + if (CurrentAI->Priority_Array[i] == ANALOG_LEVEL_NULL) + len = encode_application_null(&apdu[apdu_len]); + else { + present_value = CurrentAI->Priority_Array[i]; + len = + encode_application_real(&apdu[apdu_len], + present_value); + } + /* 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 <= BACNET_MAX_PRIORITY) { + if (CurrentAI->Priority_Array[rpdata->array_index - 1] + == ANALOG_LEVEL_NULL) + apdu_len = encode_application_null(&apdu[0]); + else { + present_value = + CurrentAI->Priority_Array[rpdata->array_index - 1]; + apdu_len = + encode_application_real(&apdu[0], present_value); + } + } else { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + } + } + break; + + case PROP_RELINQUISH_DEFAULT: + present_value = CurrentAI->Relinquish_Default; + apdu_len = encode_application_real(&apdu[0], present_value); + break; + #if defined(INTRINSIC_REPORTING) case PROP_TIME_DELAY: apdu_len = @@ -447,18 +1120,6 @@ int Analog_Input_Read_Property( break; #endif - case 9997: - /* test case for real encoding-decoding unsigned value correctly */ - apdu_len = encode_application_real(&apdu[0], 90.510F); - break; - case 9998: - /* test case for unsigned encoding-decoding unsigned value correctly */ - apdu_len = encode_application_unsigned(&apdu[0], 90); - break; - case 9999: - /* test case for signed encoding-decoding negative value correctly */ - apdu_len = encode_application_signed(&apdu[0], -200); - break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; @@ -466,8 +1127,9 @@ int Analog_Input_Read_Property( break; } /* only array properties can have array options */ - if ((apdu_len >= 0) && (rpdata->object_property != PROP_EVENT_TIME_STAMPS) - && (rpdata->array_index != BACNET_ARRAY_ALL)) { + if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) && + (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; apdu_len = BACNET_STATUS_ERROR; @@ -480,11 +1142,23 @@ int Analog_Input_Read_Property( bool Analog_Input_Write_Property( BACNET_WRITE_PROPERTY_DATA * wp_data) { + ANALOG_INPUT_DESCR *CurrentAI; bool status = false; /* return value */ - unsigned int object_index = 0; + unsigned index = 0; + int object_type = 0; + uint32_t object_instance = 0; + unsigned int priority = 0; + uint8_t level = ANALOG_LEVEL_NULL; int len = 0; BACNET_APPLICATION_DATA_VALUE value; - ANALOG_INPUT_DESCR *CurrentAI; + ctx = ucix_init("bacnet_ai"); + const char *idx_c; + char cur_value[16]; + float pvalue; + int i; + time_t cur_value_time; + char idx_cc[64]; + /* decode the some of the request */ len = @@ -497,34 +1171,123 @@ bool Analog_Input_Write_Property( wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; return false; } - /* only array properties can have array options */ - if ((wp_data->object_property != PROP_EVENT_TIME_STAMPS) && + if ((wp_data->object_property != PROP_PRIORITY_ARRAY) && + (wp_data->object_property != PROP_EVENT_TIME_STAMPS) && (wp_data->array_index != BACNET_ARRAY_ALL)) { + /* only array properties can have array options */ wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; 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 { + if (Analog_Input_Valid_Instance(wp_data->object_instance)) { + index = Analog_Input_Instance_To_Index(wp_data->object_instance); + CurrentAI = &AI_Descr[index]; + sprintf(idx_cc,"%d",CurrentAI->Instance); + idx_c = idx_cc; + } else return false; - } - switch ((int) 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); + switch (wp_data->object_property) { + case PROP_OBJECT_NAME: + if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { + /* All the object names in a device must be unique */ + if (Device_Valid_Object_Name(&value.type.Character_String, + &object_type, &object_instance)) { + if ((object_type == wp_data->object_type) && + (object_instance == wp_data->object_instance)) { + /* writing same name to same object */ + status = true; + } else { + status = false; + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_DUPLICATE_NAME; + } } else { + status = Analog_Input_Object_Name_Write( + wp_data->object_instance, + &value.type.Character_String, + &wp_data->error_class, + &wp_data->error_code); + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_DESCRIPTION: + if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { + status = Analog_Input_Description_Write( + wp_data->object_instance, + &value.type.Character_String, + &wp_data->error_class, + &wp_data->error_code); + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_PRESENT_VALUE: + if (value.tag == BACNET_APPLICATION_TAG_REAL) { + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + if (Analog_Input_Present_Value_Set(wp_data->object_instance, + value.type.Real, wp_data->priority)) { + status = true; + sprintf(cur_value,"%f",value.type.Real); + ucix_add_option(ctx, "bacnet_ai", idx_c, "value", + cur_value); + cur_value_time = time(NULL); + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "value_time", + cur_value_time); + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "write", + 1); + } else if (wp_data->priority == 6) { + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - status = false; + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL, + &wp_data->error_class, &wp_data->error_code); + if (status) { + level = ANALOG_LEVEL_NULL; + priority = wp_data->priority; + if (priority && (priority <= BACNET_MAX_PRIORITY)) { + priority--; + CurrentAI->Priority_Array[priority] = level; + /* Note: you could set the physical output here to the next + highest priority, or to the relinquish default if no + priorities are set. + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the + main loop (i.e. check out of service before changing output) */ + pvalue = CurrentAI->Relinquish_Default; + for (i = 0; i < BACNET_MAX_PRIORITY; i++) { + if (CurrentAI->Priority_Array[i] != ANALOG_LEVEL_NULL) { + pvalue = CurrentAI->Priority_Array[i]; + break; + } + } + sprintf(cur_value,"%f",pvalue); + ucix_add_option(ctx, "bacnet_ai", idx_c, "value", + cur_value); + cur_value_time = time(NULL); + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "value_time", + cur_value_time); + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "write", + 1); + } else { + status = false; + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } } } break; @@ -538,6 +1301,24 @@ bool Analog_Input_Write_Property( } break; + case PROP_RELIABILITY: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, + &wp_data->error_class, &wp_data->error_code); + if (status) { + CurrentAI->Reliability = value.type.Enumerated; + } + break; + + case PROP_COV_INCREMENT: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL, + &wp_data->error_class, &wp_data->error_code); + if (status) { + CurrentAI->COV_Increment = value.type.Real; + } + break; + case PROP_UNITS: status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, @@ -547,6 +1328,15 @@ bool Analog_Input_Write_Property( } break; + case PROP_RELINQUISH_DEFAULT: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL, + &wp_data->error_class, &wp_data->error_code); + if (status) { + CurrentAI->Relinquish_Default = value.type.Real; + } + break; + #if defined(INTRINSIC_REPORTING) case PROP_TIME_DELAY: status = @@ -556,6 +1346,8 @@ bool Analog_Input_Write_Property( if (status) { CurrentAI->Time_Delay = value.type.Unsigned_Int; CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay; + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "time_delay", + value.type.Unsigned_Int); } break; @@ -566,6 +1358,8 @@ bool Analog_Input_Write_Property( if (status) { CurrentAI->Notification_Class = value.type.Unsigned_Int; + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "nc", + value.type.Unsigned_Int); } break; @@ -576,6 +1370,8 @@ bool Analog_Input_Write_Property( if (status) { CurrentAI->High_Limit = value.type.Real; + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "high_limit", + value.type.Real); } break; @@ -586,6 +1382,8 @@ bool Analog_Input_Write_Property( if (status) { CurrentAI->Low_Limit = value.type.Real; + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "low_limit", + value.type.Real); } break; @@ -596,6 +1394,8 @@ bool Analog_Input_Write_Property( if (status) { CurrentAI->Deadband = value.type.Real; + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "dead_limit", + value.type.Real); } break; @@ -607,6 +1407,8 @@ bool Analog_Input_Write_Property( if (status) { if (value.type.Bit_String.bits_used == 2) { CurrentAI->Limit_Enable = value.type.Bit_String.value[0]; + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "limit", + value.type.Bit_String.value[0]); } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; @@ -623,6 +1425,8 @@ bool Analog_Input_Write_Property( if (status) { if (value.type.Bit_String.bits_used == 3) { CurrentAI->Event_Enable = value.type.Bit_String.value[0]; + ucix_add_option_int(ctx, "bacnet_ai", idx_c, "event", + value.type.Bit_String.value[0]); } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; @@ -654,19 +1458,17 @@ bool Analog_Input_Write_Property( break; #endif case PROP_OBJECT_IDENTIFIER: - case PROP_OBJECT_NAME: case PROP_OBJECT_TYPE: case PROP_STATUS_FLAGS: case PROP_EVENT_STATE: - case PROP_DESCRIPTION: - case PROP_RELIABILITY: + case PROP_PRIORITY_ARRAY: + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; #if defined(INTRINSIC_REPORTING) case PROP_ACKED_TRANSITIONS: case PROP_EVENT_TIME_STAMPS: #endif - case 9997: - case 9998: - case 9999: wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; @@ -675,7 +1477,8 @@ bool Analog_Input_Write_Property( wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; break; } - + ucix_commit(ctx, "bacnet_ai"); + ucix_cleanup(ctx); return status; } @@ -684,21 +1487,20 @@ void Analog_Input_Intrinsic_Reporting( uint32_t object_instance) { #if defined(INTRINSIC_REPORTING) + ANALOG_INPUT_DESCR *CurrentAI; BACNET_EVENT_NOTIFICATION_DATA event_data; BACNET_CHARACTER_STRING msgText; - ANALOG_INPUT_DESCR *CurrentAI; - unsigned int object_index; + unsigned index = 0; uint8_t FromState = 0; uint8_t ToState; float ExceededLimit = 0.0f; float PresentVal = 0.0f; bool SendNotify = false; - - object_index = Analog_Input_Instance_To_Index(object_instance); - if (object_index < MAX_ANALOG_INPUTS) - CurrentAI = &AI_Descr[object_index]; - else + if (Analog_Input_Valid_Instance(object_instance)) { + index = Analog_Input_Instance_To_Index(object_instance); + CurrentAI = &AI_Descr[index]; + } else return; /* check limits */ @@ -983,13 +1785,14 @@ int Analog_Input_Event_Information( unsigned index, BACNET_GET_EVENT_INFORMATION_DATA * getevent_data) { + //ANALOG_INPUT_DESCR *CurrentAI; bool IsNotAckedTransitions; bool IsActiveEvent; int i; /* check index */ - if (index < MAX_ANALOG_INPUTS) { + if (Analog_Input_Valid_Instance(index)) { /* Event_State not equal to NORMAL */ IsActiveEvent = (AI_Descr[index].Event_State != EVENT_STATE_NORMAL); @@ -1052,22 +1855,20 @@ int Analog_Input_Event_Information( return 0; /* no active event at this index */ } - int Analog_Input_Alarm_Ack( BACNET_ALARM_ACK_DATA * alarmack_data, BACNET_ERROR_CODE * error_code) { ANALOG_INPUT_DESCR *CurrentAI; - unsigned int object_index; + unsigned index = 0; - - object_index = - Analog_Input_Instance_To_Index(alarmack_data->eventObjectIdentifier. - instance); - - if (object_index < MAX_ANALOG_INPUTS) - CurrentAI = &AI_Descr[object_index]; - else { + if (Analog_Input_Valid_Instance(alarmack_data->eventObjectIdentifier. + instance)) { + index = + Analog_Input_Instance_To_Index(alarmack_data->eventObjectIdentifier. + instance); + CurrentAI = &AI_Descr[index]; + } else { *error_code = ERROR_CODE_UNKNOWN_OBJECT; return -1; } @@ -1089,7 +1890,7 @@ int Analog_Input_Alarm_Ack( return -1; } - /* FIXME: Send ack notification */ + /* Clean transitions flag. */ CurrentAI->Acked_Transitions[TRANSITION_TO_OFFNORMAL]. bIsAcked = true; } else { @@ -1099,29 +1900,6 @@ int Analog_Input_Alarm_Ack( break; case EVENT_STATE_FAULT: - 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_FAULT].bIsAcked = - true; - } else { - *error_code = ERROR_CODE_INVALID_EVENT_STATE; - return -1; - } - break; - - case EVENT_STATE_NORMAL: if (CurrentAI->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked == false) { if (alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME) { @@ -1135,7 +1913,30 @@ int Analog_Input_Alarm_Ack( return -1; } - /* FIXME: Send ack notification */ + /* Clean transitions flag. */ + 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; + } + + /* Clean transitions flag. */ CurrentAI->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked = true; } else { @@ -1147,9 +1948,12 @@ int Analog_Input_Alarm_Ack( default: return -2; } + + /* Need to send AckNotification. */ CurrentAI->Ack_notify_data.bSendAckNotify = true; CurrentAI->Ack_notify_data.EventState = alarmack_data->eventStateAcked; + /* Return OK */ return 1; } @@ -1157,9 +1961,10 @@ int Analog_Input_Alarm_Summary( unsigned index, BACNET_GET_ALARM_SUMMARY_DATA * getalarm_data) { + //ANALOG_INPUT_DESCR *CurrentAI; /* check index */ - if (index < MAX_ANALOG_INPUTS) { + if (index < max_analog_inputs_int) { /* Event_State is not equal to NORMAL and Notify_Type property value is ALARM */ if ((AI_Descr[index].Event_State != EVENT_STATE_NORMAL) && @@ -1205,32 +2010,24 @@ bool WPValidateArgType( BACNET_ERROR_CLASS * pErrorClass, BACNET_ERROR_CODE * pErrorCode) { - bool bResult; + pValue = pValue; + ucExpectedTag = ucExpectedTag; + pErrorClass = pErrorClass; + pErrorCode = pErrorCode; - /* - * start out assuming success and only set up error - * response if validation fails. - */ - bResult = true; - if (pValue->tag != ucExpectedTag) { - bResult = false; - *pErrorClass = ERROR_CLASS_PROPERTY; - *pErrorCode = ERROR_CODE_INVALID_DATA_TYPE; - } - - return (bResult); + return false; } -void testAnalogInput( +void testAnalog_Input( Test * pTest) { + BACNET_READ_PROPERTY_DATA rpdata; uint8_t apdu[MAX_APDU] = { 0 }; int len = 0; uint32_t len_value = 0; uint8_t tag_number = 0; - uint32_t decoded_instance = 0; uint16_t decoded_type = 0; - BACNET_READ_PROPERTY_DATA rpdata; + uint32_t decoded_instance = 0; Analog_Input_Init(); rpdata.application_data = &apdu[0]; @@ -1259,7 +2056,7 @@ int main( pTest = ct_create("BACnet Analog Input", NULL); /* individual tests */ - rc = ct_addTestFunction(pTest, testAnalogInput); + rc = ct_addTestFunction(pTest, testAnalog_Input); assert(rc); ct_setStream(pTest, stdout); diff --git a/demo/object/ai.h b/demo/object/ai.h index dce6732..5bf8852 100644 --- a/demo/object/ai.h +++ b/demo/object/ai.h @@ -1,7 +1,8 @@ /************************************************************************** * -* Copyright (C) 2005 Steve Karg +* Copyright (C) 2006 Steve Karg * Copyright (C) 2011 Krzysztof Malorny +* Copyright (C) 2013 Patrick Grimm * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -29,25 +30,38 @@ #include #include #include "bacdef.h" -#include "rp.h" +#include "cov.h" +#include "bacerror.h" #include "wp.h" +#include "rp.h" #if defined(INTRINSIC_REPORTING) #include "nc.h" -#include "getevent.h" #include "alarm_ack.h" +#include "getevent.h" #include "get_alarm_sum.h" -#endif +#endif /* INTRINSIC_REPORTING */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct analog_input_descr { + uint32_t Instance; + char Object_Name[64]; + char Object_Description[64]; + //uint8_t Present_Value; unsigned Event_State:3; - float Present_Value; - BACNET_RELIABILITY Reliability; bool Out_Of_Service; + bool Change_Of_Value; + uint8_t Reliability; + float COV_Increment; + bool Disable; uint8_t Units; + /* Here is our Priority Array. They are supposed to be Real, but */ + /* we don't have that kind of memory, so we will use a single byte */ + /* and load a Real for returning the value when asked. */ + float Priority_Array[BACNET_MAX_PRIORITY]; + float Relinquish_Default; #if defined(INTRINSIC_REPORTING) uint32_t Time_Delay; uint32_t Notification_Class; @@ -63,9 +77,29 @@ extern "C" { uint32_t Remaining_Time_Delay; /* AckNotification informations */ ACK_NOTIFICATION Ack_notify_data; -#endif +#endif /* INTRINSIC_REPORTING */ } ANALOG_INPUT_DESCR; +/* value/name tuples */ +struct ai_inst_tuple { + char idx[18]; + struct ai_inst_tuple *next; +}; + +typedef struct ai_inst_tuple ai_inst_tuple_t; + +/* structure to hold tuple-list and uci context during iteration */ +struct ai_inst_itr_ctx { + struct ai_inst_tuple *list; + struct uci_context *ctx; + char *section; +}; + + + void Analog_Input_Load_UCI_List( + const char *sec_idx, + struct ai_inst_itr_ctx *itr); + void Analog_Input_Property_Lists( const int **pRequired, const int **pOptional, @@ -73,50 +107,72 @@ extern "C" { bool Analog_Input_Valid_Instance( uint32_t object_instance); + unsigned Analog_Input_Count( void); + uint32_t Analog_Input_Index_To_Instance( unsigned index); + unsigned Analog_Input_Instance_To_Index( - uint32_t instance); + uint32_t object_instance); + + int Analog_Input_Read_Property( + BACNET_READ_PROPERTY_DATA * rpdata); + + bool Analog_Input_Write_Property( + BACNET_WRITE_PROPERTY_DATA * wp_data); + + /* optional API */ bool Analog_Input_Object_Instance_Add( uint32_t instance); bool Analog_Input_Object_Name( uint32_t object_instance, BACNET_CHARACTER_STRING * object_name); + bool Analog_Input_Name_Set( uint32_t object_instance, char *new_name); - char *Analog_Input_Description( - uint32_t instance); - bool Analog_Input_Description_Set( - uint32_t instance, - char *new_name); - - bool Analog_Input_Units_Set( - uint32_t instance, - uint16_t units); - uint16_t Analog_Input_Units( - uint32_t instance); - - int Analog_Input_Read_Property( - BACNET_READ_PROPERTY_DATA * rpdata); - bool Analog_Input_Write_Property( - BACNET_WRITE_PROPERTY_DATA * wp_data); + bool Analog_Input_Present_Value_Set( + uint32_t object_instance, + float value, + uint8_t priority); float Analog_Input_Present_Value( uint32_t object_instance); - void Analog_Input_Present_Value_Set( - uint32_t object_instance, - float value); + + unsigned Analog_Input_Present_Value_Priority( + uint32_t object_instance); bool Analog_Input_Out_Of_Service( uint32_t object_instance); + void Analog_Input_Out_Of_Service_Set( uint32_t object_instance, - bool oos_flag); + bool value); + + uint8_t Analog_Input_Reliability( + uint32_t object_instance); + + void Analog_Input_Reliability_Set( + uint32_t object_instance, + uint8_t value); + + bool Analog_Input_Encode_Value_List( + uint32_t object_instance, + BACNET_PROPERTY_VALUE * value_list); + + bool Analog_Input_Change_Of_Value( + uint32_t instance); + + void Analog_Input_Change_Of_Value_Clear( + uint32_t instance); + + bool Analog_Input_Description_Set( + uint32_t object_instance, + char *text_string); /* note: header of Intrinsic_Reporting function is required even when INTRINSIC_REPORTING is not defined */ @@ -142,7 +198,7 @@ extern "C" { #ifdef TEST #include "ctest.h" - void testAnalogInput( + void testAnalog_Input( Test * pTest); #endif diff --git a/demo/object/ao.c b/demo/object/ao.c index 7676d4e..87f935e 100644 --- a/demo/object/ao.c +++ b/demo/object/ao.c @@ -25,7 +25,7 @@ * *********************************************************************/ -/* Analog Value Objects - customize for your use */ +/* Analog Output Objects - customize for your use */ #include #include @@ -46,8 +46,7 @@ /* number of demo objects */ #ifndef MAX_ANALOG_OUTPUTS -//#define MAX_ANALOG_OUTPUTS 65535 -#define MAX_ANALOG_OUTPUTS 512 +#define MAX_ANALOG_OUTPUTS 65535 #endif unsigned max_analog_outputs_int = 0; @@ -60,11 +59,8 @@ unsigned max_analog_outputs_int = 0; /* will be relinquished (i.e. set to the NULL level). */ #define ANALOG_LEVEL_NULL 255 - - ANALOG_OUTPUT_DESCR AO_Descr[MAX_ANALOG_OUTPUTS]; - /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Analog_Output_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, @@ -119,6 +115,26 @@ void Analog_Output_Property_Lists( return; } +void Analog_Output_Load_UCI_List(const char *sec_idx, + struct ao_inst_itr_ctx *itr) +{ + ao_inst_tuple_t *t = malloc(sizeof(ao_inst_tuple_t)); + bool disable; + disable = ucix_get_option_int(itr->ctx, itr->section, sec_idx, + "disable", 0); + if (strcmp(sec_idx,"default") == 0) + return; + if (disable) + return; + if( (t = (ao_inst_tuple_t *)malloc(sizeof(ao_inst_tuple_t))) != NULL ) { + strncpy(t->idx, sec_idx, sizeof(t->idx)); + t->next = itr->list; + itr->list = t; + } + return; +} + + void Analog_Output_Init( void) { @@ -158,12 +174,29 @@ void Analog_Output_Init( const char *ucicov_increment; const char *ucicov_increment_default; const char *sec = "bacnet_ao"; + + char *section; + char *type; + struct ao_inst_itr_ctx itr_m; + section = "bacnet_ao"; + +#if PRINT_ENABLED fprintf(stderr, "Analog_Output_Init\n"); +#endif if (!initialized) { initialized = true; ctx = ucix_init(sec); +#if PRINT_ENABLED if(!ctx) fprintf(stderr, "Failed to load config file bacnet_ao\n"); +#endif + type = "ao"; + ao_inst_tuple_t *cur = malloc(sizeof (ao_inst_tuple_t)); + itr_m.list = NULL; + itr_m.section = section; + itr_m.ctx = ctx; + ucix_for_each_section_type(ctx, section, type, + (void *)Analog_Output_Load_UCI_List, &itr_m); ucidescription_default = ucix_get_option(ctx, sec, "default", "description"); @@ -187,21 +220,21 @@ void Analog_Output_Init( "dead_limit"); ucicov_increment_default = ucix_get_option(ctx, sec, "default", "cov_increment"); - - for (i = 0; i < MAX_ANALOG_OUTPUTS; i++) { - memset(&AO_Descr[i], 0x00, sizeof(ANALOG_OUTPUT_DESCR)); - /* initialize all the analog output priority arrays to NULL */ - for (j = 0; j < BACNET_MAX_PRIORITY; j++) { - AO_Descr[i].Priority_Array[j] = ANALOG_LEVEL_NULL; - } - sprintf(idx_cc,"%d",i); + i = 0; + for( cur = itr_m.list; cur; cur = cur->next ) { + strncpy(idx_cc, cur->idx, sizeof(idx_cc)); idx_c = idx_cc; uciname = ucix_get_option(ctx, "bacnet_ao", idx_c, "name"); ucidisable = ucix_get_option_int(ctx, "bacnet_ao", idx_c, "disable", 0); if ((uciname != 0) && (ucidisable == 0)) { + memset(&AO_Descr[i], 0x00, sizeof(ANALOG_OUTPUT_DESCR)); + /* initialize all the analog output priority arrays to NULL */ + for (j = 0; j < BACNET_MAX_PRIORITY; j++) { + AO_Descr[i].Priority_Array[j] = ANALOG_LEVEL_NULL; + } + AO_Descr[i].Instance=atoi(idx_cc); AO_Descr[i].Disable=false; - max_analog_outputs_int = i+1; sprintf(name, "%s", uciname); ucix_string_copy(AO_Descr[i].Object_Name, sizeof(AO_Descr[i].Object_Name), name); @@ -312,7 +345,7 @@ void Analog_Output_Init( AO_Descr[i].Event_State = EVENT_STATE_NORMAL; /* notification class not connected */ if (ucinc > -1) AO_Descr[i].Notification_Class = ucinc; - else AO_Descr[i].Notification_Class = BACNET_MAX_INSTANCE; + else AO_Descr[i].Notification_Class = 0; if (ucievent > -1) AO_Descr[i].Event_Enable = ucievent; else AO_Descr[i].Event_Enable = 0; if (ucitime_delay > -1) AO_Descr[i].Time_Delay = ucitime_delay; @@ -339,11 +372,13 @@ void Analog_Output_Init( handler_get_alarm_summary_set(OBJECT_ANALOG_OUTPUT, Analog_Output_Alarm_Summary); #endif - } else { - AO_Descr[i].Disable=true; + i++; + max_analog_outputs_int = i; } } +#if PRINT_ENABLED fprintf(stderr, "max_analog_outputs %i\n", max_analog_outputs_int); +#endif if(ctx) ucix_cleanup(ctx); } @@ -356,12 +391,17 @@ void Analog_Output_Init( unsigned Analog_Output_Instance_To_Index( uint32_t object_instance) { - unsigned index = max_analog_outputs_int; - - if (object_instance < max_analog_outputs_int) - index = object_instance; - - return index; + ANALOG_OUTPUT_DESCR *CurrentAO; + int index,instance,i; + index = max_analog_outputs_int; + for (i = 0; i < index; i++) { + CurrentAO = &AO_Descr[i]; + instance = CurrentAO->Instance; + if (CurrentAO->Instance == object_instance) { + return i; + } + } + return MAX_ANALOG_OUTPUTS; } /* we simply have 0-n object instances. Yours might be */ @@ -371,16 +411,10 @@ uint32_t Analog_Output_Index_To_Instance( unsigned index) { ANALOG_OUTPUT_DESCR *CurrentAO; - if (index < max_analog_outputs_int) { - CurrentAO = &AO_Descr[index]; - if (CurrentAO->Disable == false) { - return index; - } else { - return false; - } - } else { - return false; - } + uint32_t instance; + CurrentAO = &AO_Descr[index]; + instance = CurrentAO->Instance; + return instance; } /* we simply have 0-n object instances. Yours might be */ @@ -400,14 +434,15 @@ bool Analog_Output_Valid_Instance( ANALOG_OUTPUT_DESCR *CurrentAO; unsigned index = 0; /* offset from instance lookup */ index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { - CurrentAO = &AO_Descr[index]; - if (CurrentAO->Disable == false) { - return true; - } else { - return false; - } + if (index == MAX_ANALOG_OUTPUTS) { +#if PRINT_ENABLED + fprintf(stderr, "Analog_Output_Valid_Instance %i invalid\n",object_instance); +#endif + return false; } + CurrentAO = &AO_Descr[index]; + if (CurrentAO->Disable == false) + return true; return false; } @@ -417,10 +452,10 @@ bool Analog_Output_Change_Of_Value( { ANALOG_OUTPUT_DESCR *CurrentAO; bool status = false; - unsigned index; + unsigned index = 0; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; status = CurrentAO->Change_Of_Value; } @@ -432,10 +467,10 @@ void Analog_Output_Change_Of_Value_Clear( uint32_t object_instance) { ANALOG_OUTPUT_DESCR *CurrentAO; - unsigned index; + unsigned index = 0; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; CurrentAO->Change_Of_Value = false; } @@ -495,8 +530,8 @@ float Analog_Output_Present_Value( unsigned index = 0; /* offset from instance lookup */ unsigned i = 0; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; /* When all the priorities are level null, the present value returns */ /* the Relinquish Default value */ @@ -520,8 +555,8 @@ unsigned Analog_Output_Present_Value_Priority( unsigned i = 0; /* loop counter */ unsigned priority = 0; /* return value */ - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; for (i = 0; i < BACNET_MAX_PRIORITY; i++) { if (CurrentAO->Priority_Array[priority] != ANALOG_LEVEL_NULL) { @@ -534,7 +569,6 @@ unsigned Analog_Output_Present_Value_Priority( return priority; } - bool Analog_Output_Present_Value_Set( uint32_t object_instance, float value, @@ -544,8 +578,8 @@ bool Analog_Output_Present_Value_Set( unsigned index = 0; /* offset from instance lookup */ bool status = false; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; if (priority && (priority <= BACNET_MAX_PRIORITY) && (priority != 6 /* reserved */ ) ) { @@ -566,7 +600,6 @@ bool Analog_Output_Present_Value_Set( return status; } - bool Analog_Output_Present_Value_Relinquish( uint32_t object_instance, unsigned priority) @@ -601,8 +634,8 @@ bool Analog_Output_Out_Of_Service( unsigned index = 0; /* offset from instance lookup */ bool value = false; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; value = CurrentAO->Out_Of_Service; } @@ -617,8 +650,8 @@ void Analog_Output_Out_Of_Service_Set( ANALOG_OUTPUT_DESCR *CurrentAO; unsigned index = 0; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; CurrentAO->Out_Of_Service = value; } @@ -633,8 +666,8 @@ void Analog_Output_Reliability_Set( ANALOG_OUTPUT_DESCR *CurrentAO; unsigned index = 0; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; CurrentAO->Reliability = value; } @@ -649,8 +682,8 @@ uint8_t Analog_Output_Reliability( unsigned index = 0; /* offset from instance lookup */ uint8_t value = 0; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; value = CurrentAO->Reliability; } @@ -665,8 +698,8 @@ static char *Analog_Output_Description( unsigned index = 0; /* offset from instance lookup */ char *pName = NULL; /* return value */ - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; pName = CurrentAO->Object_Description; } @@ -683,8 +716,8 @@ bool Analog_Output_Description_Set( size_t i = 0; /* loop counter */ bool status = false; /* return value */ - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; status = true; if (new_name) { @@ -718,8 +751,8 @@ static bool Analog_Output_Description_Write( const char *idx_c; char idx_cc[64]; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; length = characterstring_length(char_string); if (length <= sizeof(CurrentAO->Object_Description)) { @@ -733,14 +766,16 @@ static bool Analog_Output_Description_Write( *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } else { - sprintf(idx_cc,"%d",index); + sprintf(idx_cc,"%d",CurrentAO->Instance); idx_c = idx_cc; if(ctx) { ucix_add_option(ctx, "bacnet_ao", idx_c, "description", char_string->value); +#if PRINT_ENABLED } else { fprintf(stderr, "Failed to open config file bacnet_ao\n"); +#endif } } } else { @@ -764,10 +799,8 @@ bool Analog_Output_Object_Name( ANALOG_OUTPUT_DESCR *CurrentAO; unsigned index = 0; /* offset from instance lookup */ bool status = false; - - index = Analog_Output_Instance_To_Index(object_instance); - - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; status = characterstring_init_ansi(object_name, CurrentAO->Object_Name); } @@ -789,8 +822,8 @@ static bool Analog_Output_Object_Name_Write( const char *idx_c; char idx_cc[64]; - index = Analog_Output_Instance_To_Index(object_instance); - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); CurrentAO = &AO_Descr[index]; length = characterstring_length(char_string); if (length <= sizeof(CurrentAO->Object_Name)) { @@ -804,14 +837,16 @@ static bool Analog_Output_Object_Name_Write( *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } else { - sprintf(idx_cc,"%d",index); + sprintf(idx_cc,"%d",CurrentAO->Instance); idx_c = idx_cc; if(ctx) { ucix_add_option(ctx, "bacnet_ao", idx_c, "name", char_string->value); +#if PRINT_ENABLED } else { fprintf(stderr, "Failed to open config file bacnet_ao\n"); +#endif } } } else { @@ -837,7 +872,7 @@ int Analog_Output_Read_Property( BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; float present_value = 0; - unsigned object_index = 0; + unsigned index = 0; unsigned i = 0; uint8_t *apdu = NULL; @@ -848,10 +883,10 @@ int Analog_Output_Read_Property( apdu = rpdata->application_data; - object_index = Analog_Output_Instance_To_Index(rpdata->object_instance); - if (object_index < max_analog_outputs_int) - CurrentAO = &AO_Descr[object_index]; - else + if (Analog_Output_Valid_Instance(rpdata->object_instance)) { + index = Analog_Output_Instance_To_Index(rpdata->object_instance); + CurrentAO = &AO_Descr[index]; + } else return BACNET_STATUS_ERROR; switch (rpdata->object_property) { @@ -1136,7 +1171,7 @@ bool Analog_Output_Write_Property( { ANALOG_OUTPUT_DESCR *CurrentAO; bool status = false; /* return value */ - unsigned int object_index = 0; + unsigned index = 0; int object_type = 0; uint32_t object_instance = 0; unsigned int priority = 0; @@ -1171,10 +1206,10 @@ bool Analog_Output_Write_Property( wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; return false; } - object_index = Analog_Output_Instance_To_Index(wp_data->object_instance); - if (object_index < max_analog_outputs_int) { - CurrentAO = &AO_Descr[object_index]; - sprintf(idx_cc,"%d",object_index); + if (Analog_Output_Valid_Instance(wp_data->object_instance)) { + index = Analog_Output_Instance_To_Index(wp_data->object_instance); + CurrentAO = &AO_Descr[index]; + sprintf(idx_cc,"%d",CurrentAO->Instance); idx_c = idx_cc; } else return false; @@ -1482,18 +1517,17 @@ void Analog_Output_Intrinsic_Reporting( ANALOG_OUTPUT_DESCR *CurrentAO; BACNET_EVENT_NOTIFICATION_DATA event_data; BACNET_CHARACTER_STRING msgText; - unsigned int object_index; + unsigned index = 0; uint8_t FromState = 0; uint8_t ToState; float ExceededLimit = 0.0f; float PresentVal = 0.0f; bool SendNotify = false; - - object_index = Analog_Output_Instance_To_Index(object_instance); - if (object_index < max_analog_outputs_int) - CurrentAO = &AO_Descr[object_index]; - else + if (Analog_Output_Valid_Instance(object_instance)) { + index = Analog_Output_Instance_To_Index(object_instance); + CurrentAO = &AO_Descr[index]; + } else return; /* check limits */ @@ -1785,7 +1819,7 @@ int Analog_Output_Event_Information( /* check index */ - if (index < max_analog_outputs_int) { + if (Analog_Output_Valid_Instance(index)) { /* Event_State not equal to NORMAL */ IsActiveEvent = (AO_Descr[index].Event_State != EVENT_STATE_NORMAL); @@ -1853,16 +1887,15 @@ int Analog_Output_Alarm_Ack( BACNET_ERROR_CODE * error_code) { ANALOG_OUTPUT_DESCR *CurrentAO; - unsigned int object_index; + unsigned index = 0; - - object_index = - Analog_Output_Instance_To_Index(alarmack_data->eventObjectIdentifier. - instance); - - if (object_index < max_analog_outputs_int) - CurrentAO = &AO_Descr[object_index]; - else { + if (Analog_Output_Valid_Instance(alarmack_data->eventObjectIdentifier. + instance)) { + index = + Analog_Output_Instance_To_Index(alarmack_data->eventObjectIdentifier. + instance); + CurrentAO = &AO_Descr[index]; + } else { *error_code = ERROR_CODE_UNKNOWN_OBJECT; return -1; } @@ -2048,7 +2081,7 @@ int main( Test *pTest; bool rc; - pTest = ct_create("BACnet Analog Value", NULL); + pTest = ct_create("BACnet Analog Output", NULL); /* individual tests */ rc = ct_addTestFunction(pTest, testAnalog_Output); assert(rc); diff --git a/demo/object/ao.h b/demo/object/ao.h index db617cd..eb71e4c 100644 --- a/demo/object/ao.h +++ b/demo/object/ao.h @@ -31,6 +31,7 @@ #include #include "bacdef.h" #include "cov.h" +#include "bacerror.h" #include "wp.h" #include "rp.h" #if defined(INTRINSIC_REPORTING) @@ -44,10 +45,8 @@ extern "C" { #endif /* __cplusplus */ -int max_analog_outputs; - typedef struct analog_output_descr { - unsigned Object_ID; + uint32_t Instance; char Object_Name[64]; char Object_Description[64]; //uint8_t Present_Value; @@ -81,6 +80,25 @@ int max_analog_outputs; #endif /* INTRINSIC_REPORTING */ } ANALOG_OUTPUT_DESCR; +/* value/name tuples */ +struct ao_inst_tuple { + char idx[18]; + struct ao_inst_tuple *next; +}; + +typedef struct ao_inst_tuple ao_inst_tuple_t; + +/* structure to hold tuple-list and uci context during iteration */ +struct ao_inst_itr_ctx { + struct ao_inst_tuple *list; + struct uci_context *ctx; + char *section; +}; + + + void Analog_Output_Load_UCI_List( + const char *sec_idx, + struct ao_inst_itr_ctx *itr); void Analog_Output_Property_Lists( const int **pRequired, diff --git a/demo/object/bv.c b/demo/object/bv.c index 81b9c28..0ccdda5 100644 --- a/demo/object/bv.c +++ b/demo/object/bv.c @@ -471,7 +471,7 @@ void Binary_Value_Out_Of_Service_Set( return; } -uint8_t Binary_Value_Reliabvlity( +uint8_t Binary_Value_Reliability( uint32_t object_instance) { BINARY_VALUE_DESCR *CurrentBV; @@ -481,13 +481,13 @@ uint8_t Binary_Value_Reliabvlity( if (Binary_Value_Valid_Instance(object_instance)) { index = Binary_Value_Instance_To_Index(object_instance); CurrentBV = &BV_Descr[index]; - value = CurrentBV->Reliabvlity; + value = CurrentBV->Reliability; } return value; } -void Binary_Value_Reliabvlity_Set( +void Binary_Value_Reliability_Set( uint32_t object_instance, uint8_t value) { @@ -497,7 +497,7 @@ void Binary_Value_Reliabvlity_Set( if (Binary_Value_Valid_Instance(object_instance)) { index = Binary_Value_Instance_To_Index(object_instance); CurrentBV = &BV_Descr[index]; - CurrentBV->Reliabvlity = value; + CurrentBV->Reliability = value; } return; @@ -1054,7 +1054,7 @@ int Binary_Value_Read_Property( case PROP_RELIABILITY: apdu_len = encode_application_enumerated(&apdu[0], - CurrentBV->Reliabvlity); + CurrentBV->Reliability); break; case PROP_PRIORITY_ARRAY: @@ -1416,7 +1416,7 @@ bool Binary_Value_Write_Property( WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class, &wp_data->error_code); if (status) { - CurrentBV->Reliabvlity = value.type.Enumerated; + CurrentBV->Reliability = value.type.Enumerated; } break; diff --git a/demo/object/device.c b/demo/object/device.c index 35c1e93..2f84cc3 100644 --- a/demo/object/device.c +++ b/demo/object/device.c @@ -107,7 +107,6 @@ static object_functions_t My_Object_Table[] = { NULL /* COV */ , NULL /* COV Clear */ , NULL /* Intrinsic Reporting */ }, -#if 0 {OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, @@ -119,9 +118,9 @@ static object_functions_t My_Object_Table[] = { Analog_Input_Property_Lists, NULL /* ReadRangeInfo */ , NULL /* Iterator */ , - NULL /* Value_Lists */ , - NULL /* COV */ , - NULL /* COV Clear */ , + Analog_Input_Encode_Value_List , + Analog_Input_Change_Of_Value, + Analog_Input_Change_Of_Value_Clear, Analog_Input_Intrinsic_Reporting}, {OBJECT_ANALOG_OUTPUT, Analog_Output_Init, @@ -137,8 +136,7 @@ static object_functions_t My_Object_Table[] = { Analog_Output_Encode_Value_List , Analog_Output_Change_Of_Value, Analog_Output_Change_Of_Value_Clear, - Analog_Value_Intrinsic_Reporting}, -#endif + Analog_Output_Intrinsic_Reporting}, {OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count,