From 3dfa360ef5a472dde4abc4397f1d22e95d84374e Mon Sep 17 00:00:00 2001 From: Patrick Grimm Date: Sat, 21 Sep 2013 04:19:45 +0200 Subject: [PATCH] load uci value if uci config has mod time change --- demo/object/av.c | 178 ++++++++++++++++++++++++++++++++++------- demo/object/av.h | 25 +++++- demo/object/bi.c | 1 + demo/object/device.c | 22 +++-- demo/object/trendlog.c | 2 +- demo/server/main.c | 88 +++++++++++++++++++- include/ucix.h | 23 ++++++ src/ucix.c | 55 +++++++++++++ 8 files changed, 350 insertions(+), 44 deletions(-) diff --git a/demo/object/av.c b/demo/object/av.c index 92da1b5..882db7d 100644 --- a/demo/object/av.c +++ b/demo/object/av.c @@ -94,6 +94,7 @@ static const int Analog_Value_Properties_Optional[] = { PROP_NOTIFY_TYPE, PROP_EVENT_TIME_STAMPS, #endif + PROP_RELIABILITY, -1 }; @@ -149,42 +150,43 @@ void Analog_Value_Init( const char *ucilow_limit; const char *ucidead_limit_default; const char *ucidead_limit; + const char *sec = "bacnet_av"; fprintf(stderr, "Analog_Value_Init\n"); if (!initialized) { initialized = true; - ctx = ucix_init("bacnet_av"); + ctx = ucix_init(sec); if(!ctx) - fprintf(stderr, "Failed to load config file"); - - ucidescription_default = ucix_get_option(ctx, "bacnet_av", "default", + fprintf(stderr, "Failed to load config file\n"); + + ucidescription_default = ucix_get_option(ctx, sec, "default", "description"); - uciunit_default = ucix_get_option_int(ctx, "bacnet_av", "default", + uciunit_default = ucix_get_option_int(ctx, sec, "default", "si_unit", 0); - ucivalue_default = ucix_get_option(ctx, "bacnet_av", "default", + ucivalue_default = ucix_get_option(ctx, sec, "default", "value"); - ucinc_default = ucix_get_option_int(ctx, "bacnet_av", "default", + ucinc_default = ucix_get_option_int(ctx, sec, "default", "nc", -1); - ucievent_default = ucix_get_option_int(ctx, "bacnet_av", "default", + ucievent_default = ucix_get_option_int(ctx, sec, "default", "event", -1); - ucitime_delay_default = ucix_get_option_int(ctx, "bacnet_av", "default", + ucitime_delay_default = ucix_get_option_int(ctx, sec, "default", "time_delay", -1); - ucilimit_default = ucix_get_option_int(ctx, "bacnet_av", "default", + ucilimit_default = ucix_get_option_int(ctx, sec, "default", "limit", -1); - ucihigh_limit_default = ucix_get_option(ctx, "bacnet_av", "default", + ucihigh_limit_default = ucix_get_option(ctx, sec, "default", "high_limit"); - ucilow_limit_default = ucix_get_option(ctx, "bacnet_av", "default", + ucilow_limit_default = ucix_get_option(ctx, sec, "default", "low_limit"); - ucidead_limit_default = ucix_get_option(ctx, "bacnet_av", "default", + ucidead_limit_default = ucix_get_option(ctx, sec, "default", "dead_limit"); - + for (i = 0; i < MAX_ANALOG_VALUES; i++) { memset(&AV_Descr[i], 0x00, sizeof(ANALOG_VALUE_DESCR)); /* initialize all the analog output priority arrays to NULL */ for (j = 0; j < BACNET_MAX_PRIORITY; j++) { AV_Descr[i].Priority_Array[j] = ANALOG_LEVEL_NULL; } - sprintf(idx_cc,"%d",i); - idx_c = idx_cc; + sprintf(idx_cc,"%d",i); + idx_c = idx_cc; uciname = ucix_get_option(ctx, "bacnet_av", idx_c, "name"); ucidisable = ucix_get_option_int(ctx, "bacnet_av", idx_c, "disable", 0); @@ -216,7 +218,7 @@ void Analog_Value_Init( } else { AV_Descr[i].Units = UNITS_PERCENT; } - + ucivalue = ucix_get_option(ctx, "bacnet_av", idx_c, "value"); if (ucivalue == NULL) { @@ -224,14 +226,16 @@ void Analog_Value_Init( ucivalue = 0; } else { ucivalue = ucivalue_default; + AV_Descr[i].Reliability = + RELIABILITY_COMMUNICATION_FAILURE; } } AV_Descr[i].Priority_Array[15] = strtof(ucivalue, (char **) NULL); AV_Descr[i].Relinquish_Default = 0; //TODO read uci - - #if defined(INTRINSIC_REPORTING) + +#if defined(INTRINSIC_REPORTING) ucinc = ucix_get_option_int(ctx, "bacnet_av", idx_c, "nc", ucinc_default); ucievent = ucix_get_option_int(ctx, "bacnet_av", idx_c, @@ -280,14 +284,14 @@ void Analog_Value_Init( AV_Descr[i].High_Limit = strtof(ucihigh_limit, (char **) NULL); AV_Descr[i].Low_Limit = strtof(ucilow_limit, (char **) NULL); AV_Descr[i].Deadband = strtof(ucidead_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(&AV_Descr[i].Event_Time_Stamps[j]); AV_Descr[i].Acked_Transitions[j].bIsAcked = true; } - + /* Set handler for GetEventInformation function */ handler_get_event_information_set(OBJECT_ANALOG_VALUE, Analog_Value_Event_Information); @@ -296,7 +300,7 @@ void Analog_Value_Init( /* Set handler for GetAlarmSummary Service */ handler_get_alarm_summary_set(OBJECT_ANALOG_VALUE, Analog_Value_Alarm_Summary); - #endif +#endif } else { AV_Descr[i].Disable=true; } @@ -369,6 +373,81 @@ bool Analog_Value_Valid_Instance( return false; } +bool Analog_Value_Change_Of_Value( + uint32_t object_instance) +{ + ANALOG_VALUE_DESCR *CurrentAV; + bool status = false; + unsigned index; + + index = Analog_Value_Instance_To_Index(object_instance); + if (index < max_analog_values_int) { + CurrentAV = &AV_Descr[index]; + status = CurrentAV->Change_Of_Value; + } + + return status; +} + +void Analog_Value_Change_Of_Value_Clear( + uint32_t object_instance) +{ + ANALOG_VALUE_DESCR *CurrentAV; + unsigned index; + + index = Analog_Value_Instance_To_Index(object_instance); + if (index < max_analog_values_int) { + CurrentAV = &AV_Descr[index]; + CurrentAV->Change_Of_Value = false; + } + + return; +} + + +/* returns true if value has changed */ +bool Analog_Value_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_Value_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_Value_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_Value_Change_Of_Value(object_instance); + + return status; +} + float Analog_Value_Present_Value( uint32_t object_instance) { @@ -407,10 +486,9 @@ bool Analog_Value_Present_Value_Set( if (index < max_analog_values_int) { CurrentAV = &AV_Descr[index]; if (priority && (priority <= BACNET_MAX_PRIORITY) && - (priority != 6 /* reserved */ ) && - (value >= 0.0) && (value <= 100.0)) { - CurrentAV->Present_Value = (uint8_t) value; - CurrentAV->Priority_Array[priority - 1] = (uint8_t) value; + (priority != 6 /* reserved */ ) ) { + //CurrentAV->Present_Value = value; + CurrentAV->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. @@ -439,6 +517,38 @@ bool Analog_Value_Out_Of_Service( return value; } +void Analog_Value_Reliability_Set( + uint32_t object_instance, + uint8_t value) +{ + ANALOG_VALUE_DESCR *CurrentAV; + unsigned index = 0; + + index = Analog_Value_Instance_To_Index(object_instance); + if (index < max_analog_values_int) { + CurrentAV = &AV_Descr[index]; + CurrentAV->Reliability = value; + } + + return; +} + +uint8_t Analog_Value_Reliability( + uint32_t object_instance) +{ + ANALOG_VALUE_DESCR *CurrentAV; + unsigned index = 0; /* offset from instance lookup */ + uint8_t value = 0; + + index = Analog_Value_Instance_To_Index(object_instance); + if (index < max_analog_values_int) { + CurrentAV = &AV_Descr[index]; + value = CurrentAV->Reliability; + } + + return value; +} + void Analog_Value_Out_Of_Service_Set( uint32_t object_instance, bool value) @@ -456,7 +566,6 @@ void Analog_Value_Out_Of_Service_Set( } - static char *Analog_Value_Description( uint32_t object_instance) { @@ -716,6 +825,12 @@ int Analog_Value_Read_Property( apdu_len = encode_application_boolean(&apdu[0], state); break; + case PROP_RELIABILITY: + case PROP_STATE_RELIABILITY: + apdu_len = encode_application_boolean(&apdu[0], + CurrentAV->Reliability); + break; + case PROP_UNITS: apdu_len = encode_application_enumerated(&apdu[0], CurrentAV->Units); @@ -1050,6 +1165,15 @@ bool Analog_Value_Write_Property( } break; + case PROP_RELIABILITY: + status = + WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, + &wp_data->error_class, &wp_data->error_code); + if (status) { + CurrentAV->Reliability = value.type.Enumerated; + } + break; + case PROP_UNITS: status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, diff --git a/demo/object/av.h b/demo/object/av.h index 2448096..929eaf3 100644 --- a/demo/object/av.h +++ b/demo/object/av.h @@ -29,7 +29,8 @@ #include #include #include "bacdef.h" -#include "bacerror.h" +#include "bacerror.h" //TODO rm ? +#include "cov.h" #include "wp.h" #include "rp.h" #if defined(INTRINSIC_REPORTING) @@ -46,11 +47,14 @@ extern "C" { int max_analog_values; typedef struct analog_value_descr { + unsigned Object_ID; char Object_Name[64]; char Object_Description[64]; - uint8_t Present_Value; + //uint8_t Present_Value; unsigned Event_State:3; bool Out_Of_Service; + uint8_t Reliability; + bool Change_Of_Value; bool Disable; uint8_t Units; /* Here is our Priority Array. They are supposed to be Real, but */ @@ -127,6 +131,23 @@ int max_analog_values; uint32_t object_instance, bool value); + uint8_t Analog_Value_Reliability( + uint32_t object_instance); + + void Analog_Value_Reliability_Set( + uint32_t object_instance, + uint8_t value); + + bool Analog_Value_Encode_Value_List( + uint32_t object_instance, + BACNET_PROPERTY_VALUE * value_list); + + bool Analog_Value_Change_Of_Value( + uint32_t instance); + + void Analog_Value_Change_Of_Value_Clear( + uint32_t instance); + bool Analog_Value_Description_Set( uint32_t object_instance, char *text_string); diff --git a/demo/object/bi.c b/demo/object/bi.c index 2fbef45..b7ee6a4 100644 --- a/demo/object/bi.c +++ b/demo/object/bi.c @@ -862,6 +862,7 @@ int Binary_Input_Read_Property( if (CurrentBI->Disable) return BACNET_STATUS_ERROR; + fprintf(stderr,"object_property: %i\n", rpdata->object_property); switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = diff --git a/demo/object/device.c b/demo/object/device.c index 20047bd..d42af89 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, @@ -138,7 +137,6 @@ static object_functions_t My_Object_Table[] = { NULL /* COV */ , NULL /* COV Clear */ , NULL /* Intrinsic Reporting */ }, -#endif {OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, @@ -150,9 +148,9 @@ static object_functions_t My_Object_Table[] = { Analog_Value_Property_Lists, NULL /* ReadRangeInfo */ , NULL /* Iterator */ , - NULL /* Value_Lists */ , - NULL /* COV */ , - NULL /* COV Clear */ , + Analog_Value_Encode_Value_List , + Analog_Value_Change_Of_Value, + Analog_Value_Change_Of_Value_Clear, Analog_Value_Intrinsic_Reporting}, {OBJECT_BINARY_INPUT, Binary_Input_Init, @@ -169,7 +167,6 @@ static object_functions_t My_Object_Table[] = { Binary_Input_Change_Of_Value, Binary_Input_Change_Of_Value_Clear, Binary_Input_Intrinsic_Reporting}, -#if 0 {OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, @@ -215,8 +212,8 @@ static object_functions_t My_Object_Table[] = { NULL /* COV */ , NULL /* COV Clear */ , NULL /* Intrinsic Reporting */ }, -#endif -#if defined(INTRINSIC_REPORTING) +//#endif +//#if defined(INTRINSIC_REPORTING) {OBJECT_NOTIFICATION_CLASS, Notification_Class_Init, Notification_Class_Count, @@ -232,8 +229,8 @@ static object_functions_t My_Object_Table[] = { NULL /* COV */ , NULL /* COV Clear */ , NULL /* Intrinsic Reporting */ }, -#endif -#if 0 +//#endif +//#if 0 {OBJECT_LIFE_SAFETY_POINT, Life_Safety_Point_Init, Life_Safety_Point_Count, @@ -294,7 +291,7 @@ static object_functions_t My_Object_Table[] = { NULL /* COV */ , NULL /* COV Clear */ , NULL /* Intrinsic Reporting */ }, -#endif +//#endif {OBJECT_MULTI_STATE_VALUE, Multistate_Value_Init, Multistate_Value_Count, @@ -325,7 +322,7 @@ static object_functions_t My_Object_Table[] = { NULL /* COV */ , NULL /* COV Clear */ , NULL /* Intrinsic Reporting */ }, -#if defined(BACFILE) +//#if defined(BACFILE) {OBJECT_FILE, bacfile_init, bacfile_count, @@ -341,7 +338,6 @@ static object_functions_t My_Object_Table[] = { NULL /* COV */ , NULL /* COV Clear */ , NULL /* Intrinsic Reporting */ }, -#endif {MAX_BACNET_OBJECT_TYPE, NULL /* Init */ , NULL /* Count */ , diff --git a/demo/object/trendlog.c b/demo/object/trendlog.c index dda9ca4..76f5110 100644 --- a/demo/object/trendlog.c +++ b/demo/object/trendlog.c @@ -227,7 +227,7 @@ void Trend_Log_Init( if ((uciname != 0) && (ucidisable == 0)) { TL_Descr[i].Disable=false; max_trend_logs_int = i+1; - sprintf(name, "%s", uciname); + sprintf(name, "TL_%s", uciname); ucix_string_copy(TL_Descr[i].Object_Name, sizeof(TL_Descr[i].Object_Name), name); ucidescription = ucix_get_option(ctxd, uciobject_s, diff --git a/demo/server/main.c b/demo/server/main.c index 4104717..1623a16 100644 --- a/demo/server/main.c +++ b/demo/server/main.c @@ -60,7 +60,8 @@ #include "bacfile.h" #endif /* defined(BACFILE) */ #include "ucix.h" - +#include "av.h" +#include "bi.h" /** @file server/main.c Example server application using the BACnet Stack. */ @@ -160,7 +161,15 @@ int main( uint32_t address_binding_tmr = 0; uint32_t recipient_scan_tmr = 0; int uci_id = 0; + float val_f, pval_f; + int val_i, pval_i; struct uci_context *ctx; + time_t chk_mtime = 0; + time_t ucimodtime_bacnet_bi = 0; + time_t ucimodtime_bacnet_av = 0; + int uci_idx = 0; + char *section; + char *type; ctx = ucix_init("bacnet_dev"); if(!ctx) @@ -235,6 +244,83 @@ int main( #endif /* output */ + /* update Analog Value from uci */ + section = "bacnet_av"; + type = "av"; + chk_mtime = 0; + chk_mtime = check_uci_update(section, ucimodtime_bacnet_av); + if(chk_mtime != 0) { + ucimodtime_bacnet_av = chk_mtime; + printf("Config changed, reloading %s\n",section); + ctx = ucix_init(section); + struct uci_itr_ctx itr; + value_tuple_t *cur; + itr.list = NULL; + itr.section = section; + itr.ctx = ctx; + ucix_for_each_section_type(ctx, section, type, + (void *)load_value, &itr); + for( cur = itr.list; cur; cur = cur->next ) { + printf("section %s idx %s \n", section, cur->idx); + val_f = strtof(cur->value,NULL); + uci_idx = atoi(cur->idx); + if (val_f || !strcmp(cur->value, "0")) { + printf("idx %s ",cur->idx); + printf("value %s\n",cur->value); + pval_f = Analog_Value_Present_Value(uci_idx); + if ( val_f != pval_f ) { + Analog_Value_Present_Value_Set(uci_idx,val_f,16); + } + if (Analog_Value_Out_Of_Service(uci_idx)) + Analog_Value_Out_Of_Service_Set(uci_idx,0); + if (Analog_Value_Reliability(uci_idx)) + Analog_Value_Reliability_Set(uci_idx, + RELIABILITY_NO_FAULT_DETECTED); + } else { + printf("idx %s ",cur->idx); + printf("Out_Of_Service\n"); + Analog_Value_Out_Of_Service_Set(uci_idx,1); + Analog_Value_Reliability_Set(uci_idx, + RELIABILITY_COMMUNICATION_FAILURE); + } + } + ucix_cleanup(ctx); + } + /* update end */ + + /* update Binary Input from uci */ + section = "bacnet_bi"; + type = "bi"; + chk_mtime = 0; + chk_mtime = check_uci_update(section, ucimodtime_bacnet_bi); + if(chk_mtime != 0) { + ucimodtime_bacnet_bi = chk_mtime; + printf("Config changed, reloading %s\n",section); + ctx = ucix_init(section); + struct uci_itr_ctx itr; + value_tuple_t *cur; + itr.list = NULL; + itr.section = section; + itr.ctx = ctx; + ucix_for_each_section_type(ctx, section, type, + (void *)load_value, &itr); + for( cur = itr.list; cur; cur = cur->next ) { + printf("section %s idx %s \n", section, cur->idx); + if (cur->value) { + printf("idx %s ",cur->idx); + printf("value %s\n",cur->value); + val_i = atoi(cur->value); + uci_idx = atoi(cur->idx); + pval_i = Binary_Input_Present_Value(uci_idx); + if ( val_i != pval_i ) { + Binary_Input_Present_Value_Set(uci_idx,val_i,16); + } + } + } + ucix_cleanup(ctx); + } + /* update end */ + /* blink LEDs, Turn on or off outputs, etc */ } diff --git a/include/ucix.h b/include/ucix.h index f99174a..08f1d24 100644 --- a/include/ucix.h +++ b/include/ucix.h @@ -16,10 +16,29 @@ * Copyright (C) 2008 John Crispin */ +#include +#include + #ifndef _UCI_H__ #define _UCI_H__ struct uci_context* ucix_init(const char *config_file); struct uci_context* ucix_init_path(const char *path, const char *config_file); + +/* value/name tuples */ +struct value_tuple { + char value[16]; + char idx[18]; + struct value_tuple *next; +}; + +/* structure to hold tuple-list and uci context during iteration */ +struct uci_itr_ctx { + struct value_tuple *list; + struct uci_context *ctx; + char *section; +}; +typedef struct value_tuple value_tuple_t; + void ucix_cleanup(struct uci_context *ctx); void ucix_save(struct uci_context *ctx); void ucix_save_state(struct uci_context *ctx); @@ -46,4 +65,8 @@ bool ucix_string_copy(char *dest, size_t i, char *src); void ucix_for_each_section_type(struct uci_context *ctx, const char *p, const char *t, void (*cb)(const char*, void*), void *priv); +/* Check if given uci file was updated */ +time_t check_uci_update(const char *config, time_t mtime); +/* Add tuple */ +void load_value(const char *sec_idx, struct uci_itr_ctx *itr); #endif diff --git a/src/ucix.c b/src/ucix.c index ac96e9f..cdc3f4c 100644 --- a/src/ucix.c +++ b/src/ucix.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -241,3 +243,56 @@ bool ucix_string_copy(char *dest, size_t j, char *src) return false; } +/* Check if given uci file was updated */ +time_t check_uci_update(const char *config, time_t mtime) +{ + struct stat s; + char path[128]; + time_t f_mtime = 0; + + snprintf(path, sizeof(path), "/var/state/%s", config); + if( stat(path, &s) > -1 ) + f_mtime = s.st_mtime; + + snprintf(path, sizeof(path), "/etc/config/%s", config); + if( stat(path, &s) > -1 ) { + if( (f_mtime == 0) || (s.st_mtime > f_mtime) ) { + f_mtime = s.st_mtime; + } + } + + snprintf(path, sizeof(path), "/tmp/.uci/%s", config); + if( stat(path, &s) > -1 ) { + if( (f_mtime == 0) || (s.st_mtime > f_mtime) ) { + f_mtime = s.st_mtime; + } + } + if( (mtime == 0) || (f_mtime > mtime) ) { + return f_mtime; + } else { + f_mtime = 0; + } + return f_mtime; +} + +/* Add tuple */ +void load_value(const char *sec_idx, struct uci_itr_ctx *itr) +{ + value_tuple_t *t; + + if (!strcmp(sec_idx, "default")) + return; + + const char *value; + value = ucix_get_option(itr->ctx, itr->section, sec_idx, "value"); + if( (t = (value_tuple_t *)malloc(sizeof(value_tuple_t))) != NULL ) { + strncpy(t->idx, sec_idx, sizeof(t->idx)); + if ( value != NULL ) { + strncpy(t->value, value, sizeof(t->value)); + } + t->next = itr->list; + itr->list = t; + } +} + +