From 15cb616b4ae3091fc393c04df22b888bdc6c9840 Mon Sep 17 00:00:00 2001 From: skarg Date: Mon, 15 Apr 2013 20:22:24 +0000 Subject: [PATCH] Added UCI support for the BACnet demo server. UCI is a replacement for nvram. The source is GPL and has a lua lib. http://wiki.openwrt.org/doc/uci http://nbd.name/gitweb.cgi?p=uci.git;a=summary Thank you, Patrick . --- bacnet-stack/Makefile | 8 +- bacnet-stack/demo/Makefile | 7 +- bacnet-stack/demo/object/device.c | 21 +++- bacnet-stack/demo/server/main.c | 26 ++++- bacnet-stack/doc/bacnet_dev.config | 5 + bacnet-stack/include/ucix.h | 41 +++++++ bacnet-stack/lib/Makefile | 3 + bacnet-stack/src/ucix.c | 175 +++++++++++++++++++++++++++++ 8 files changed, 279 insertions(+), 7 deletions(-) create mode 100644 bacnet-stack/doc/bacnet_dev.config create mode 100644 bacnet-stack/include/ucix.h create mode 100644 bacnet-stack/src/ucix.c diff --git a/bacnet-stack/Makefile b/bacnet-stack/Makefile index 9f1b2b05..1ec64eac 100644 --- a/bacnet-stack/Makefile +++ b/bacnet-stack/Makefile @@ -17,6 +17,10 @@ MY_BACNET_DEFINES += -DBACFILE MY_BACNET_DEFINES += -DINTRINSIC_REPORTING BACNET_DEFINES ?= $(MY_BACNET_DEFINES) +# un-comment the next line to build in uci integration +#BACNET_DEFINES += -DBAC_UCI +#UCI_LIB_DIR ?= /usr/local/lib + #BACDL_DEFINE=-DBACDL_ETHERNET=1 #BACDL_DEFINE=-DBACDL_ARCNET=1 #BACDL_DEFINE=-DBACDL_MSTP=1 @@ -34,7 +38,7 @@ MAKE_DEFINE ?= DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE) $(BBMD_DEFINE) -DWEAK_FUNC= DEFINES += $(MAKE_DEFINE) -# BACnet Ports Directory +# BACnet Ports Directory BACNET_PORT ?= linux # Default compiler settings @@ -64,7 +68,7 @@ demos: $(MAKE) -s -C demo all gateway: - $(MAKE) -B -s -C demo gateway + $(MAKE) -B -s -C demo gateway router: $(MAKE) -s -C demo router diff --git a/bacnet-stack/demo/Makefile b/bacnet-stack/demo/Makefile index 2f9550a9..35db4c3b 100644 --- a/bacnet-stack/demo/Makefile +++ b/bacnet-stack/demo/Makefile @@ -21,7 +21,12 @@ BACNET_LIB_TARGET = $(BACNET_LIB_DIR)/lib$(BACNET_LIB_NAME).a INCLUDE1 = -I$(BACNET_PORT_DIR) -I$(BACNET_OBJECT) -I$(BACNET_HANDLER) INCLUDE2 = -I$(BACNET_INCLUDE) INCLUDES = $(INCLUDE1) $(INCLUDE2) -BACNET_LIB=-L$(BACNET_LIB_DIR),-l$(BACNET_LIB_NAME) +BACNET_LIB := -L$(BACNET_LIB_DIR),-l$(BACNET_LIB_NAME) +# build for UCI +ifneq (,$(findstring -DBAC_UCI,$(BACNET_DEFINES))) +BACNET_LIB = $(BACNET_LIB),-L$(UCI_LIB_DIR),-luci +endif +# OS specific builds ifeq (${BACNET_PORT},linux) PFLAGS = -pthread TARGET_EXT = diff --git a/bacnet-stack/demo/object/device.c b/bacnet-stack/demo/object/device.c index a8f97cb2..3b6e310d 100644 --- a/bacnet-stack/demo/object/device.c +++ b/bacnet-stack/demo/object/device.c @@ -67,6 +67,9 @@ #if defined(BACFILE) #include "bacfile.h" #endif /* defined(BACFILE) */ +#if defined(BAC_UCI) +#include "ucix.h" +#endif /* defined(BAC_UCI) */ #if defined(__BORLANDC__) @@ -1810,8 +1813,24 @@ void Device_Init( object_functions_t * object_table) { struct object_functions *pObject = NULL; +#if defined(BAC_UCI) + const char *uciname; + struct uci_context *ctx; + fprintf(stderr, "Device_Init\n"); + ctx = ucix_init("bacnet_dev"); + if(!ctx) + fprintf(stderr, "Failed to load config file bacnet_dev\n"); + uciname = ucix_get_option(ctx, "bacnet_dev", "0", "Name"); + if (uciname != 0) { + characterstring_init_ansi(&My_Object_Name, uciname); + } else { +#endif /* defined(BAC_UCI) */ + characterstring_init_ansi(&My_Object_Name, "SimpleServer"); +#if defined(BAC_UCI) + } + ucix_cleanup(ctx); +#endif /* defined(BAC_UCI) */ - characterstring_init_ansi(&My_Object_Name, "SimpleServer"); if (object_table) { Object_Table = object_table; } else { diff --git a/bacnet-stack/demo/server/main.c b/bacnet-stack/demo/server/main.c index 092a2dc9..95bb8337 100644 --- a/bacnet-stack/demo/server/main.c +++ b/bacnet-stack/demo/server/main.c @@ -59,6 +59,9 @@ #if defined(BACFILE) #include "bacfile.h" #endif /* defined(BACFILE) */ +#if defined(BAC_UCI) +#include "ucix.h" +#endif /* defined(BAC_UCI) */ /** @file server/main.c Example server application using the BACnet Stack. */ @@ -158,10 +161,27 @@ int main( uint32_t elapsed_milliseconds = 0; uint32_t address_binding_tmr = 0; uint32_t recipient_scan_tmr = 0; +#if defined(BAC_UCI) + int uciId = 0; + struct uci_context *ctx; + + ctx = ucix_init("bacnet_dev"); + if(!ctx) + fprintf(stderr, "Failed to load config file bacnet_dev\n"); + uciId = ucix_get_option_int(ctx, "bacnet_dev", "0", "Id", 0); + printf("ID: %i", uciId); + if (uciId != 0) { + Device_Set_Object_Instance_Number(uciId); + } else { +#endif /* defined(BAC_UCI) */ + /* allow the device ID to be set */ + if (argc > 1) + Device_Set_Object_Instance_Number(strtol(argv[1], NULL, 0)); +#if defined(BAC_UCI) + } + ucix_cleanup(ctx); +#endif /* defined(BAC_UCI) */ - /* allow the device ID to be set */ - if (argc > 1) - Device_Set_Object_Instance_Number(strtol(argv[1], NULL, 0)); printf("BACnet Server Demo\n" "BACnet Stack Version %s\n" "BACnet Device ID: %u\n" "Max APDU: %d\n", BACnet_Version, Device_Object_Instance_Number(), MAX_APDU); diff --git a/bacnet-stack/doc/bacnet_dev.config b/bacnet-stack/doc/bacnet_dev.config new file mode 100644 index 00000000..0ca7138c --- /dev/null +++ b/bacnet-stack/doc/bacnet_dev.config @@ -0,0 +1,5 @@ + +config dev '0' + option Description 'Simple BACnet Device' + option Name 'SampleDevice' + option Id 10042 diff --git a/bacnet-stack/include/ucix.h b/bacnet-stack/include/ucix.h new file mode 100644 index 00000000..ea9af200 --- /dev/null +++ b/bacnet-stack/include/ucix.h @@ -0,0 +1,41 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2008 John Crispin + */ + +#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); +void ucix_cleanup(struct uci_context *ctx); +void ucix_save(struct uci_context *ctx); +void ucix_save_state(struct uci_context *ctx); +const char* ucix_get_option(struct uci_context *ctx, + const char *p, const char *s, const char *o); +int ucix_get_option_int(struct uci_context *ctx, + const char *p, const char *s, const char *o, int def); +void ucix_add_section(struct uci_context *ctx, + const char *p, const char *s, const char *t); +void ucix_add_option(struct uci_context *ctx, + const char *p, const char *s, const char *o, const char *t); +void ucix_add_option_int(struct uci_context *ctx, + const char *p, const char *s, const char *o, int t); +int ucix_commit(struct uci_context *ctx, const char *p); +void ucix_revert(struct uci_context *ctx, + const char *p, const char *s, const char *o); +void ucix_del(struct uci_context *ctx, const char *p, + const char *s, const char *o); +#endif diff --git a/bacnet-stack/lib/Makefile b/bacnet-stack/lib/Makefile index 74b9a20a..8bd60710 100644 --- a/bacnet-stack/lib/Makefile +++ b/bacnet-stack/lib/Makefile @@ -193,6 +193,9 @@ endif ifdef BACDL_ALL PORT_SRC = ${PORT_ALL_SRC} endif +ifneq (,$(findstring -DBAC_UCI,$(BACNET_DEFINES))) +UCI_SRC = $(BACNET_CORE)/ucix.c +endif SRCS = ${CORE_SRC} ${PORT_SRC} ${HANDLER_SRC} ${OBJECT_SRC} diff --git a/bacnet-stack/src/ucix.c b/bacnet-stack/src/ucix.c new file mode 100644 index 00000000..fe20ebca --- /dev/null +++ b/bacnet-stack/src/ucix.c @@ -0,0 +1,175 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2008 John Crispin + */ + +#include +#include +#include + +#include +#include +#include "ucix.h" +//#include "log.h" + +static struct uci_ptr ptr; + +static inline int ucix_get_ptr(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t) +{ + memset(&ptr, 0, sizeof(ptr)); + ptr.package = p; + ptr.section = s; + ptr.option = o; + ptr.value = t; + return uci_lookup_ptr(ctx, &ptr, NULL, true); +} + +struct uci_context* ucix_init(const char *config_file) +{ + struct uci_context *ctx = uci_alloc_context(); +// uci_add_history_path(ctx, "/var/state"); + uci_add_delta_path(ctx, "/var/state"); + if(uci_load(ctx, config_file, NULL) != UCI_OK) + { + fprintf(stderr, "%s/%s is missing or corrupt\n", ctx->savedir, config_file); + return NULL; + } + return ctx; +} + +struct uci_context* ucix_init_path(const char *path, const char *config_file) +{ + struct uci_context *ctx = uci_alloc_context(); + if(path) + uci_set_confdir(ctx, path); + if(uci_load(ctx, config_file, NULL) != UCI_OK) + { + fprintf(stderr, "%s/%s is missing or corrupt\n", ctx->savedir, config_file); + return NULL; + } + return ctx; +} + +void ucix_cleanup(struct uci_context *ctx) +{ + uci_free_context(ctx); +} + +void ucix_save(struct uci_context *ctx) +{ + uci_set_savedir(ctx, "/tmp/.uci/"); + uci_save(ctx, NULL); +} + +void ucix_save_state(struct uci_context *ctx) +{ + uci_set_savedir(ctx, "/var/state/"); + uci_save(ctx, NULL); +} + +const char* ucix_get_option(struct uci_context *ctx, const char *p, const char *s, const char *o) +{ + struct uci_element *e = NULL; + const char *value = NULL; + if(ucix_get_ptr(ctx, p, s, o, NULL)) + return NULL; + if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) + return NULL; + e = ptr.last; + switch (e->type) + { + case UCI_TYPE_SECTION: + value = uci_to_section(e)->type; + break; + case UCI_TYPE_OPTION: + switch(ptr.o->type) { + case UCI_TYPE_STRING: + value = ptr.o->v.string; + break; + default: + value = NULL; + break; + } + break; + default: + return 0; + } + + return value; +} + +int ucix_get_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int def) +{ + const char *tmp = ucix_get_option(ctx, p, s, o); + int ret = def; + + if (tmp) + ret = atoi(tmp); + return ret; +} + +void ucix_add_section(struct uci_context *ctx, const char *p, const char *s, const char *t) +{ + if(ucix_get_ptr(ctx, p, s, NULL, t)) + return; + uci_set(ctx, &ptr); +} + +void ucix_add_option(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t) +{ + if(ucix_get_ptr(ctx, p, s, o, (t)?(t):(""))) + return; + uci_set(ctx, &ptr); +} + +void ucix_add_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int t) +{ + char tmp[64]; + snprintf(tmp, 64, "%d", t); + ucix_add_option(ctx, p, s, o, tmp); +} + +void ucix_del(struct uci_context *ctx, const char *p, const char *s, const char *o) +{ + if(!ucix_get_ptr(ctx, p, s, o, NULL)) + uci_delete(ctx, &ptr); +} + +void ucix_revert(struct uci_context *ctx, const char *p, const char *s, const char *o) +{ + if(!ucix_get_ptr(ctx, p, s, o, NULL)) + uci_revert(ctx, &ptr); +} + +void ucix_for_each_section_type(struct uci_context *ctx, + const char *p, const char *t, + void (*cb)(const char*, void*), void *priv) +{ + struct uci_element *e; + if(ucix_get_ptr(ctx, p, NULL, NULL, NULL)) + return; + uci_foreach_element(&ptr.p->sections, e) + if (!strcmp(t, uci_to_section(e)->type)) + cb(e->name, priv); +} + +int ucix_commit(struct uci_context *ctx, const char *p) +{ + if(ucix_get_ptr(ctx, p, NULL, NULL, NULL)) + return 1; + return uci_commit(ctx, &ptr.p, false); +} +