From 229e6ad7d8b4f914e50bde5c062102c184b0571a Mon Sep 17 00:00:00 2001 From: RTL <24235755+Telemechanics@users.noreply.github.com> Date: Tue, 20 May 2025 08:52:09 +0200 Subject: [PATCH] examples/xedge_demo: Add Xedge IoT Toolkit with BAS integration Add support for Xedge, an embedded software toolkit for IoT applications using Lua scripting with HTTP(S), WebSockets, MQTT, and device I/O. * netutils/xedge: Dependency manager that downloads BAS library and BAS-Resources, generates XedgeZip.c during build * examples/xedge_demo: Complete example showing Xedge integration with HTTP server, Lua runtime, and SNTP time synchronization Signed-off-by: Jorge Guzman --- examples/xedge_demo/Kconfig | 41 +++++ examples/xedge_demo/Make.defs | 24 +++ examples/xedge_demo/Makefile | 30 ++++ examples/xedge_demo/xedge_main.c | 278 +++++++++++++++++++++++++++++++ netutils/xedge/.gitignore | 3 + netutils/xedge/Kconfig | 23 +++ netutils/xedge/Make.defs | 27 +++ netutils/xedge/Makefile | 98 +++++++++++ 8 files changed, 524 insertions(+) create mode 100644 examples/xedge_demo/Kconfig create mode 100644 examples/xedge_demo/Make.defs create mode 100644 examples/xedge_demo/Makefile create mode 100644 examples/xedge_demo/xedge_main.c create mode 100644 netutils/xedge/.gitignore create mode 100644 netutils/xedge/Kconfig create mode 100644 netutils/xedge/Make.defs create mode 100644 netutils/xedge/Makefile diff --git a/examples/xedge_demo/Kconfig b/examples/xedge_demo/Kconfig new file mode 100644 index 00000000000..9bc02d0fadf --- /dev/null +++ b/examples/xedge_demo/Kconfig @@ -0,0 +1,41 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_XEDGE_DEMO + tristate "Xedge IoT Toolkit Demo" + depends on NETUTILS_XEDGE && ALLOW_GPL_COMPONENTS + default n + ---help--- + Simple demonstration of the Xedge IoT Toolkit library. + + This example shows how to integrate and use the Xedge library + in your NuttX application. Xedge provides a high-level development + environment for creating IoT and industrial device applications + using Lua scripting with access to HTTP(S), WebSockets, MQTT, + file system, and device I/O. + + Note: This example requires the NETUTILS_XEDGE library to be enabled. + +if EXAMPLES_XEDGE_DEMO + +config EXAMPLES_XEDGE_DEMO_PROGNAME + string "Program name" + default "xedge_demo" + ---help--- + This is the name of the ELF executable for the Xedge demo application in NSH. + +config EXAMPLES_XEDGE_DEMO_PRIORITY + int "Xedge demo task priority" + default 100 + ---help--- + Set the task priority for the Xedge demo application. + +config EXAMPLES_XEDGE_DEMO_STACKSIZE + int "Xedge demo stack size" + default 20000 + ---help--- + Set the stack size for the Xedge demo application. + +endif diff --git a/examples/xedge_demo/Make.defs b/examples/xedge_demo/Make.defs new file mode 100644 index 00000000000..cf0d076cebd --- /dev/null +++ b/examples/xedge_demo/Make.defs @@ -0,0 +1,24 @@ +############################################################################ +# apps/examples/xedge_demo/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_XEDGE_DEMO),) +CONFIGURED_APPS += $(APPDIR)/examples/xedge_demo +CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/netutils/xedge/BAS/inc ${INCDIR_PREFIX}$(APPDIR)/netutils/xedge/BAS/inc/arch/Posix ${INCDIR_PREFIX}$(APPDIR)/netutils/xedge/BAS/inc/arch/NET/Posix -DNO_INIT_DISK_IO -DUSE_DBGMON=1 -DUSE_IPV6 +endif \ No newline at end of file diff --git a/examples/xedge_demo/Makefile b/examples/xedge_demo/Makefile new file mode 100644 index 00000000000..ff40b851267 --- /dev/null +++ b/examples/xedge_demo/Makefile @@ -0,0 +1,30 @@ +############################################################################ +# apps/examples/xedge_demo/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +PROGNAME = $(CONFIG_EXAMPLES_XEDGE_DEMO_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_XEDGE_DEMO_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_XEDGE_DEMO_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_XEDGE_DEMO) + +MAINSRC = xedge_main.c + +include $(APPDIR)/Application.mk \ No newline at end of file diff --git a/examples/xedge_demo/xedge_main.c b/examples/xedge_demo/xedge_main.c new file mode 100644 index 00000000000..2aae637e953 --- /dev/null +++ b/examples/xedge_demo/xedge_main.c @@ -0,0 +1,278 @@ +/*************************************************************************** + * apps/examples/xedge_demo/xedge_main.c + * + * Copyright (C) 2025. All rights reserved. + * Author: Real Time Logic + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Dunkels. + * 4. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +/* Xedge NuttX Startup Code (may need adjustments) + * + * Additional License Note: Xedge, based on the Barracuda + * App Server, uses the license options explained here: + * https://github.com/RealTimeLogic/BAS#license + * This repo does not include Xedge and the Barracuda App Server + * library and must be downloaded separately. The dependencies + * are automatically downloaded in apps/netutils/xedge/. + */ + +/*************************************************************************** + * Included Files + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../netutils/xedge/BAS/examples/xedge/src/xedge.h" + +/*************************************************************************** + * Pre-processor Definitions + ***************************************************************************/ + +/* The following is a horrible hack to make the code pass the NuttX + * checkpatch.sh tool. The Barracuda App Server uses a type of + * camelCase encoding as explained here: + * https://realtimelogic.com/ba/doc/en/C/introduction.html#oo_c + */ + +#define ltmgr ltMgr +#define lthreadmgr LThreadMgr +#define lthreadmgr_run LThreadMgr_run +#define platforminitdiskio platformInitDiskIo +#define diskio DiskIo +#define diskio_setrootdir DiskIo_setRootDir +#define threadjob ThreadJob +#define threadjob_lcreate ThreadJob_lcreate +#define lt Lt +#define threadmutex ThreadMutex +#define threadmutex_set ThreadMutex_set +#define httpserver_getmutex HttpServer_getMutex +#define threadmutex_release ThreadMutex_release +#define xedgeinitdiskio xedgeInitDiskIo +#define batime BaTime +#define baparsedate baParseDate +#define bagetunixtime baGetUnixTime +#define thread_sleep Thread_sleep +#define bafatalerrorcodes BaFatalErrorCodes +#define setdispexit setDispExit +#define xedgeopenaux xedgeOpenAUX +#define xedgeopenauxt XedgeOpenAUX +#define httptrace_setflushcallback HttpTrace_setFLushCallback +#define httpserver_seterrhnd HttpServer_setErrHnd + +/*************************************************************************** + * Private Data + ***************************************************************************/ + +static int running = FALSE; /* Running mode: 2 running, 1 exiting, 0 stopped */ + +/* BAS is configured to use dlmalloc for NuttX. This is the pool. + * 2M : recommended minimum + */ + +static char poolbuf[2 * 1024 * 1024]; + +extern lthreadmgr ltmgr; /* The LThreadMgr configured in xedge.c */ + +/*************************************************************************** + * External Function Prototypes + ***************************************************************************/ + +/* barracuda(): BAS/examples/xedge/src/xedge.c */ + +extern void barracuda(void); +extern void init_dlmalloc(char *heapstart, char *heapend); /* dlmalloc.c */ +extern int (*platforminitdiskio)(diskio *io); /* xedge.c */ + +/*************************************************************************** + * Private Functions + ***************************************************************************/ + +/* The following two functions are copied from the example: + * https://github.com/RealTimeLogic/BAS/blob/main/examples/xedge/src/led.c + * Details: + * https://realtimelogic.com/ba/examples/xedge/readme.html#time + */ + +/* This callback is called by one of the threads managed by LThreadMgr + * when a job is taken off the queue and executed. The callback + * attempts to find the global Lua function '_XedgeEvent', and if the + * function is found, it will be executed as follows: _XedgeEvent("sntp") + */ + +static void execevent(threadjob *job, int msgh, lthreadmgr *mgr) +{ + lua_State *L = job->lt; + lua_pushglobaltable(L); + lua_getfield(L, -1, "_XedgeEvent"); + + if (lua_isfunction(L, -1)) + { + lua_pushstring(L, "sntp"); + lua_pcall(L, 1, 0, msgh); + } +} + +/* Thread started by xedgeOpenAUX() */ + +static void *checktimethread(void *arg) +{ + threadmutex *dm = httpserver_getmutex(ltmgr.server); + const char *d = __DATE__; + char buf[50]; + + (void)arg; + + if (!(basnprintf(buf, sizeof(buf), "Mon, %c%c %c%c%c %s %s", + d[4], d[5], d[0], d[1], d[2], d + 7, __TIME__) < 0)) + { + batime t = baparsedate(buf); + if (t) + { + t -= 24 * 60 * 60; + while (bagetunixtime() < t) + { + thread_sleep(500); + } + + threadjob *job = threadjob_lcreate(sizeof(threadjob), execevent); + threadmutex_set(dm); + lthreadmgr_run(<mgr, job); + threadmutex_release(dm); + } + } + + return NULL; +} + +static void panic(bafatalerrorcodes ecode1, + unsigned int ecode2, + const char *file, + int line) +{ + syslog(LOG_ERR, "Fatal error in Barracuda %d %d %s %d\n", + ecode1, ecode2, file, line); + exit(1); +} + +/* Redirect server's HttpTrace to syslog. + * https://realtimelogic.com/ba/doc/en/C/reference/html/structHttpTrace.html + */ + +static void flushtrace(char *buf, int buflen) +{ + buf[buflen] = 0; + syslog(LOG_INFO, "%s", buf); +} + +static void sighandler(int signo) +{ + if (running) + { + printf("\nGot SIGTERM; exiting...\n"); + setdispexit(); + + /* NuttX feature: Must wait for socket select() to return */ + + thread_sleep(2000); + } +} + +/*************************************************************************** + * Public Functions + ***************************************************************************/ + +/* xedge.c calls this to initialize the IO. + * Change "/mnt/lfs" to your preference. + */ + +int xedgeinitdiskio(diskio *io) +{ + if (diskio_setrootdir(io, "/mnt/lfs")) + { + syslog(LOG_ERR, "Error: cannot set root to /mnt/lfs\n"); + return -1; + } + + return 0; +} + +/* xedge.c calls this; include your Lua bindings here. + * Tutorial: https://tutorial.realtimelogic.com/Lua-Bindings.lsp + */ + +int xedgeopenaux(xedgeopenauxt *aux) +{ + pthread_t thread; + pthread_attr_t attr; + struct sched_param param; + + (void)aux; + + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 4096); + param.sched_priority = SCHED_PRIORITY_DEFAULT; + pthread_attr_setschedparam(&attr, ¶m); + pthread_create(&thread, &attr, checktimethread, NULL); + + return 0; +} + +int main(int argc, FAR char *argv[]) +{ + if (running) + { + printf("Already running!\n"); + return 1; + } + + signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); + + ntpc_start(); + init_dlmalloc(poolbuf, poolbuf + sizeof(poolbuf)); + httptrace_setflushcallback(flushtrace); + httpserver_seterrhnd(panic); + + running = TRUE; + barracuda(); + running = FALSE; + + printf("Exiting Xedge\n"); + return 0; +} diff --git a/netutils/xedge/.gitignore b/netutils/xedge/.gitignore new file mode 100644 index 00000000000..adfe77e1622 --- /dev/null +++ b/netutils/xedge/.gitignore @@ -0,0 +1,3 @@ +/BAS +/BAS-Resources +/*.o diff --git a/netutils/xedge/Kconfig b/netutils/xedge/Kconfig new file mode 100644 index 00000000000..42bc72e1c79 --- /dev/null +++ b/netutils/xedge/Kconfig @@ -0,0 +1,23 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config NETUTILS_XEDGE + tristate "Xedge IoT Toolkit Dependencies" + depends on ALLOW_GPL_COMPONENTS + default n + ---help--- + Download and prepare Xedge IoT Toolkit dependencies (BAS and BAS-Resources). + + Xedge is an embedded software toolkit designed to enable high-level developers + (e.g., web and Lua programmers) to create sophisticated, secure IoT and industrial + device applications. It abstracts low-level embedded development through a lightweight + runtime built on top of the Barracuda App Server and Lua. + + This option will download the required Barracuda App Server and BAS-Resources + repositories during the build process, making them available for applications + that want to use Xedge. + + After enabling this, you can use the examples/xedge_demo as a reference + for integrating Xedge into your own applications. \ No newline at end of file diff --git a/netutils/xedge/Make.defs b/netutils/xedge/Make.defs new file mode 100644 index 00000000000..6284a874ff6 --- /dev/null +++ b/netutils/xedge/Make.defs @@ -0,0 +1,27 @@ +############################################################################ +# apps/netutils/xedge/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_NETUTILS_XEDGE),) + +CONFIGURED_APPS += $(APPDIR)/netutils/xedge + +endif \ No newline at end of file diff --git a/netutils/xedge/Makefile b/netutils/xedge/Makefile new file mode 100644 index 00000000000..b2b51b4e455 --- /dev/null +++ b/netutils/xedge/Makefile @@ -0,0 +1,98 @@ +############################################################################ +# apps/netutils/xedge/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +BAS_UNPACKNAME = BAS +BAS_HASH = 9f74a2f778b002ad8441471b8a7a5b13172dbe76 +BAS_RESOURCES_UNPACKNAME = BAS-Resources +BAS_RESOURCES_HASH = 227a4b998300fa4cfde871dc7dac92c09e1636c2 + +BAS_ZIP_URL = https://github.com/RealTimeLogic/BAS/archive/$(BAS_HASH).zip +BAS_RESOURCES_ZIP_URL = https://github.com/RealTimeLogic/BAS-Resources/archive/$(BAS_RESOURCES_HASH).zip + +XEDGEZIP = BAS/examples/xedge/XedgeZip.c + +BAS_SRC = $(BAS_UNPACKNAME)$(DELIM)src +BAS_ARCH_SRC = $(BAS_SRC)$(DELIM)arch$(DELIM)Posix +BAS_NET_SRC = $(BAS_SRC)$(DELIM)arch$(DELIM)NET$(DELIM)generic +BAS_DISKIO_SRC = $(BAS_SRC)$(DELIM)DiskIo$(DELIM)posix +BAS_XEDGE_SRC = $(BAS_UNPACKNAME)$(DELIM)examples$(DELIM)xedge$(DELIM)src + +CFLAGS += ${INCDIR_PREFIX}$(CURDIR)/$(BAS_UNPACKNAME)/inc +CFLAGS += ${INCDIR_PREFIX}$(CURDIR)/$(BAS_UNPACKNAME)/inc/arch/Posix +CFLAGS += ${INCDIR_PREFIX}$(CURDIR)/$(BAS_UNPACKNAME)/inc/arch/NET/Posix +CFLAGS += -DNO_INIT_DISK_IO -DUSE_DBGMON=1 -DUSE_IPV6 + +VPATH += $(BAS_SRC) +VPATH += $(BAS_ARCH_SRC) +VPATH += $(BAS_NET_SRC) +VPATH += $(BAS_DISKIO_SRC) +VPATH += $(BAS_XEDGE_SRC) +VPATH += $(BAS_UNPACKNAME)/examples/xedge + +CSRCS = BAS.c dlmalloc.c ThreadLib.c SoDisp.c BaFile.c xedge.c XedgeZip.c + +# Download and prepare BAS and BAS-Resources +xedge-deps: + # ############################################################################ + # Config and Fetch xedge + # ############################################################################ + + @if [ ! -d $(BAS_UNPACKNAME) ]; then \ + echo "Downloading BAS from hash $(BAS_HASH)..."; \ + curl -f -L $(BAS_ZIP_URL) -o bas-temp.zip || \ + (echo "Error downloading BAS"; exit 1); \ + unzip -q bas-temp.zip; \ + mv BAS-$(BAS_HASH) $(BAS_UNPACKNAME); \ + rm -f bas-temp.zip; \ + fi + + @if [ ! -d $(BAS_RESOURCES_UNPACKNAME) ]; then \ + echo "Downloading BAS-Resources from hash $(BAS_RESOURCES_HASH)..."; \ + curl -f -L $(BAS_RESOURCES_ZIP_URL) -o resources-temp.zip || \ + (echo "Error downloading BAS-Resources"; exit 1); \ + unzip -q resources-temp.zip; \ + mv BAS-Resources-$(BAS_RESOURCES_HASH) $(BAS_RESOURCES_UNPACKNAME); \ + rm -f resources-temp.zip; \ + fi + + # ############################################################################ + # Library Configuration + # ############################################################################ + + @if [ ! -f "$(XEDGEZIP)" ]; then \ + echo "Creating XedgeZip.c"; \ + cd $(BAS_RESOURCES_UNPACKNAME)/build/ && \ + printf "n\nl\nn\n" | bash Xedge.sh > /dev/null && \ + cp XedgeZip.c ../../$(BAS_UNPACKNAME)/examples/xedge/ || exit 1; \ + fi + +$(CSRCS:.c=$(OBJEXT)): xedge-deps + +ifeq ($(wildcard $(BAS_UNPACKNAME)/.git),) +distclean:: xedge-deps + $(call DELDIR, $(BAS_UNPACKNAME)) + $(call DELDIR, $(BAS_RESOURCES_UNPACKNAME)) + +context:: xedge-deps +endif + +include $(APPDIR)/Application.mk \ No newline at end of file