This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new cf41b0113 netutils/libshvc: add Silicon Heaven integration into NuttX 
and SHV examples
cf41b0113 is described below

commit cf41b01135cf9305e4bc149bb110ef1056566744
Author: Stepan Pressl <[email protected]>
AuthorDate: Sun Aug 31 17:40:34 2025 +0200

    netutils/libshvc: add Silicon Heaven integration into NuttX and SHV examples
    
    This commit marks the end of my GSoC 2025 project in the NuttX section.
    All changes:
    
    - Silicon Heaven protocol (SHV) implementation:
      The library is cloned from github.com/silicon-heaven/shv-libs4c
      and compiled here. The library has out-of-the-box support
      for NuttX and possibly all posix systems.
      The library is compiled with CONFIG_SHV_LIBS4C_PLATFORM define
      set to "nuttx". The library's dependancy is Pavel Pisa's ULUT
      and originates from Michal Lenc's GSoC.
    
    - examples/shv-nxboot-updater:
      An example which constructs a SHV tree with which you can perform
      firmware updates using a SHV "file node". The file node wraps
      around NXBoot's update partition.
      The application also allows for NXBoot confirmation of the images.
      This application is to be meant used as a "background service",
      started before any apps, possibly using rcS. The tree is allocated
      as GAVL (see below).
    
    - examples/shv-test:
      An example which constructs a SHV tree and gives the user
      the ability to choose which type of construction should be used,
      either:
        - GAVL:       dynamic SHV tree allocation encapsulated within
                      an AVL tree.
        - GSA:        dynamic SHV tree allocation encapsulated within
                      a continuous array with binary search
        - GSA_STATIC: SHV tree is defined as static const, this means
                      all the data structures are placed in .rodata.
                      Extremely beneficial for embedded systems,
                      as .rodata is located in flash and embedded
                      systems usually have more flash than sram,
                      thus reducing sram usage. The downside is that
                      the definitions are rather tedious, but can
                      be automated in case of some code generation
                      (like in pysimCoder).
                      All of it is places in a continuous array with
                      binary search.
    
    Signed-off-by: Stepan Pressl <[email protected]>
---
 examples/shv-nxboot-updater/Kconfig                |  30 ++
 examples/shv-nxboot-updater/Make.defs              |  23 ++
 examples/shv-nxboot-updater/Makefile               |  31 ++
 examples/shv-nxboot-updater/shv_nxboot_updater.c   | 392 ++++++++++++++++++
 .../shv-nxboot-updater/update-script/.gitignore    |   1 +
 examples/shv-nxboot-updater/update-script/gui.py   | 236 +++++++++++
 .../update-script/requirements.txt                 |   5 +
 .../shv-nxboot-updater/update-script/shvconfirm.py |  33 ++
 .../shv-nxboot-updater/update-script/shvflasher.py |  85 ++++
 examples/shv-test/Kconfig                          |  30 ++
 examples/shv-test/Make.defs                        |  23 ++
 examples/shv-test/Makefile                         |  31 ++
 examples/shv-test/shv_test.c                       | 448 +++++++++++++++++++++
 netutils/libshvc/.gitignore                        |   2 +
 netutils/libshvc/Kconfig                           |  11 +
 netutils/libshvc/Make.defs                         |  34 ++
 netutils/libshvc/Makefile                          |  90 +++++
 netutils/libulut/.gitignore                        |   2 +
 netutils/libulut/Kconfig                           |  17 +
 netutils/libulut/Make.defs                         |  32 ++
 netutils/libulut/Makefile                          |  90 +++++
 21 files changed, 1646 insertions(+)

diff --git a/examples/shv-nxboot-updater/Kconfig 
b/examples/shv-nxboot-updater/Kconfig
new file mode 100644
index 000000000..d25da7cd0
--- /dev/null
+++ b/examples/shv-nxboot-updater/Kconfig
@@ -0,0 +1,30 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+menuconfig EXAMPLES_SHV_NXBOOT_UPDATER
+       bool "Silicon Heaven Firmware updates for NXBoot"
+       depends on NETUTILS_LIBSHVC
+       default n
+       ---help---
+               Enable the shv-nxboot-updater application.
+
+if EXAMPLES_SHV_NXBOOT_UPDATER
+
+config EXAMPLES_SHV_NXBOOT_UPDATER_PROGNAME
+       string "shv-nxboot-updater App Name"
+       default "shv_nxboot_updater"
+       ---help---
+               This is the name of the program that will be used when the NSH 
ELF
+               program is installed.
+
+config EXAMPLES_SHV_NXBOOT_UPDATER_PRIORITY
+       int "shv-nxboot-updater task priority"
+       default 100
+
+config EXAMPLES_SHV_NXBOOT_UPDATER_STACKSIZE
+       int "shv-nxboot-updater task stack size"
+       default 4096
+
+endif # EXAMPLES_NX_SHV_FWUPDATER
diff --git a/examples/shv-nxboot-updater/Make.defs 
b/examples/shv-nxboot-updater/Make.defs
new file mode 100644
index 000000000..745b86220
--- /dev/null
+++ b/examples/shv-nxboot-updater/Make.defs
@@ -0,0 +1,23 @@
+############################################################################
+# apps/examples/shv-nxboot-updater/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_SHV_NXBOOT_UPDATER),)
+CONFIGURED_APPS += $(APPDIR)/examples/shv-nxboot-updater
+endif
diff --git a/examples/shv-nxboot-updater/Makefile 
b/examples/shv-nxboot-updater/Makefile
new file mode 100644
index 000000000..339199a27
--- /dev/null
+++ b/examples/shv-nxboot-updater/Makefile
@@ -0,0 +1,31 @@
+############################################################################
+# apps/examples/shv-nxboot-updater/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
+
+MODULE = $(CONFIG_EXAMPLES_SHV_NXBOOT_UPDATER)
+
+PROGNAME  += $(CONFIG_EXAMPLES_SHV_NXBOOT_UPDATER_PROGNAME)
+PRIORITY  += $(CONFIG_EXAMPLES_SHV_NXBOOT_UPDATER_PRIORITY)
+STACKSIZE += $(CONFIG_EXAMPLES_SHV_NXBOOT_UPDATER_STACKSIZE)
+
+MAINSRC += shv_nxboot_updater.c
+
+include $(APPDIR)/Application.mk
diff --git a/examples/shv-nxboot-updater/shv_nxboot_updater.c 
b/examples/shv-nxboot-updater/shv_nxboot_updater.c
new file mode 100644
index 000000000..0a75cf727
--- /dev/null
+++ b/examples/shv-nxboot-updater/shv_nxboot_updater.c
@@ -0,0 +1,392 @@
+/****************************************************************************
+ * apps/examples/shv-nxboot-updater/shv_nxboot_updater.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <shv/tree/shv_tree.h>
+#include <shv/tree/shv_file_node.h>
+#include <shv/tree/shv_connection.h>
+#include <shv/tree/shv_methods.h>
+#include <shv/tree/shv_clayer_posix.h>
+#include <shv/tree/shv_dotdevice_node.h>
+#include <shv/tree/shv_dotapp_node.h>
+
+#include <stdio.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <semaphore.h>
+
+#include <nxboot.h>
+#include <nuttx/mtd/mtd.h>
+#include <sys/boardctl.h>
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int shv_nxboot_opener(struct shv_file_node *item);
+static int shv_fwstable_confirm(struct shv_con_ctx *shv_ctx,
+                                struct shv_node *item, int rid);
+static int shv_fwstable_get(struct shv_con_ctx *shv_ctx,
+                            struct shv_node *item, int rid);
+static void quit_handler(int signum);
+static void print_help(char *name);
+
+static struct shv_node *shv_tree_create(void);
+static void attention_cb(struct shv_con_ctx *shv_ctx,
+                         enum shv_attention_reason r);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* An execution barrier */
+
+static sem_t running;
+
+/* ------------------------- ROOT METHODS --------------------------------- */
+
+static const struct shv_method_des * const shv_dev_root_dmap_items[] =
+{
+  &shv_dmap_item_dir,
+  &shv_dmap_item_ls,
+};
+
+static const struct shv_dmap shv_dev_root_dmap =
+  SHV_CREATE_NODE_DMAP(root, shv_dev_root_dmap_items);
+
+/* ------------------------- fwstable METHODS ---------------------------- */
+
+static const struct shv_method_des shv_dev_fwstable_dmap_item_confirm =
+{
+  .name = "confirm",
+  .method = shv_fwstable_confirm
+};
+
+static const struct shv_method_des shv_dev_fwstable_dmap_item_get =
+{
+  .name = "get",
+  .method = shv_fwstable_get
+};
+
+static const struct shv_method_des * const shv_dev_fwstable_dmap_items[] =
+{
+  &shv_dev_fwstable_dmap_item_confirm,
+  &shv_dmap_item_dir,
+  &shv_dev_fwstable_dmap_item_get,
+  &shv_dmap_item_ls
+};
+
+static const struct shv_dmap shv_dev_fwstable_dmap =
+  SHV_CREATE_NODE_DMAP(dotdevice, shv_dev_fwstable_dmap_items);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int shv_fwstable_confirm(struct shv_con_ctx *shv_ctx,
+                                struct shv_node *item, int rid)
+{
+  shv_unpack_data(&shv_ctx->unpack_ctx, 0, 0);
+  nxboot_confirm();
+  shv_send_empty_response(shv_ctx, rid);
+  return 0;
+}
+
+static int shv_fwstable_get(struct shv_con_ctx *shv_ctx,
+                            struct shv_node *item, int rid)
+{
+  shv_unpack_data(&shv_ctx->unpack_ctx, 0, 0);
+  int ret = nxboot_get_confirm();
+  if (ret >= 0)
+    {
+      shv_send_int(shv_ctx, rid, ret);
+    }
+  else
+    {
+      shv_send_error(shv_ctx, rid, SHV_RE_PLATFORM_ERROR,
+                     "nxboot_get_confirm failed");
+    }
+
+  return 0;
+}
+
+static int shv_nxboot_opener(struct shv_file_node *item)
+{
+  struct shv_file_node_fctx *fctx = (struct shv_file_node_fctx *)item->fctx;
+  if (!(fctx->flags & SHV_FILE_POSIX_BITFLAG_OPENED))
+    {
+      fctx->fd = nxboot_open_update_partition();
+      if (fctx->fd < 0)
+        {
+          return -1;
+        }
+
+      fctx->flags |= SHV_FILE_POSIX_BITFLAG_OPENED;
+    }
+
+  return 0;
+}
+
+static struct shv_node *shv_tree_create(void)
+{
+  struct shv_node           *tree_root;
+  struct shv_node           *fwstable_node;
+  struct shv_dotdevice_node *dotdevice_node;
+  struct shv_file_node      *fwupdate_node;
+  struct shv_dotapp_node    *dotapp_node;
+
+  struct mtd_geometry_s geometry;
+  int flash_fd;
+  flash_fd = nxboot_open_update_partition();
+  if (flash_fd < 0)
+    {
+      return NULL;
+    }
+
+  puts("Creating the SHV Tree root");
+  tree_root = shv_tree_node_new("", &shv_dev_root_dmap, 0);
+  if (tree_root == NULL)
+    {
+      close(flash_fd);
+      return NULL;
+    }
+
+  fwupdate_node = shv_tree_file_node_new("fwUpdate",
+                                         &shv_file_node_dmap, 0);
+  if (fwupdate_node == NULL)
+    {
+      close(flash_fd);
+      free(tree_root);
+      return NULL;
+    }
+
+  if (ioctl(flash_fd, MTDIOC_GEOMETRY,
+            (unsigned long)((uintptr_t)&geometry)) < 0)
+    {
+      close(flash_fd);
+      free(tree_root);
+      free(fwupdate_node);
+      return NULL;
+    }
+
+  fwupdate_node->file_type = SHV_FILE_MTD;
+  fwupdate_node->file_maxsize = geometry.erasesize * geometry.neraseblocks;
+  fwupdate_node->file_pagesize = geometry.blocksize;
+  fwupdate_node->file_erasesize = geometry.erasesize;
+
+  /* Update the fops table in the file node */
+
+  fwupdate_node->fops.opener = shv_nxboot_opener;
+  shv_tree_add_child(tree_root, &fwupdate_node->shv_node);
+  close(flash_fd);
+
+  dotapp_node = shv_tree_dotapp_node_new(&shv_dotapp_dmap, 0);
+  if (dotapp_node == NULL)
+    {
+      free(tree_root);
+      free(fwupdate_node);
+      return NULL;
+    }
+
+  dotapp_node->name = "NuttX shv-libs4c FW Updater";
+  dotapp_node->version = "1.0.0";
+
+  shv_tree_add_child(tree_root, &dotapp_node->shv_node);
+
+  dotdevice_node = shv_tree_dotdevice_node_new(&shv_dotdevice_dmap, 0);
+  if (dotdevice_node == NULL)
+    {
+      free(tree_root);
+      free(fwupdate_node);
+      free(dotapp_node);
+      return NULL;
+    }
+
+  dotdevice_node->name = "SHV Compatible Device";
+  dotdevice_node->serial_number = "0xDEADBEEF";
+  dotdevice_node->version = "0.1.0";
+  shv_tree_add_child(tree_root, &dotdevice_node->shv_node);
+
+  fwstable_node = shv_tree_node_new("fwStable", &shv_dev_fwstable_dmap, 0);
+  if (fwstable_node == NULL)
+    {
+      free(tree_root);
+      free(fwupdate_node);
+      free(dotapp_node);
+      return NULL;
+    }
+
+  shv_tree_add_child(tree_root, fwstable_node);
+
+  return tree_root;
+}
+
+static void quit_handler(int signum)
+{
+  puts("Stopping SHV FW Updater!");
+  sem_post(&running);
+}
+
+static void print_help(char *name)
+{
+  printf("%s: [OPTIONS]\n", name);
+  puts("SHV Firmware Updater for NXBoot");
+  puts("Showcases the file handling capabilities and usage with NXBoot.");
+  puts("Mandatory options:");
+  puts("  -m <mount-point>: mount point in the SHV broker");
+  puts("  -i <ip-addr>: IPv4 address of the SHV broker");
+  puts("  -p <passwd>: password to access the SHV broker");
+  puts("  -t <port>: TCP/IP port of the SHV broker");
+  puts("  -u <user>: user to access the SHV broker");
+  puts("Nonmandatory options:");
+  puts("  -h: print help");
+}
+
+static void attention_cb(struct shv_con_ctx *shv_ctx,
+                         enum shv_attention_reason r)
+{
+  if (r == SHV_ATTENTION_ERROR)
+    {
+      printf("Error occurred in SHV, the reason is: %s\n",
+             shv_errno_str(shv_ctx));
+      sem_post(&running);
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: main
+ ****************************************************************************/
+
+int main(int argc, char *argv[])
+{
+  /* Define the SHV Communication parameters */
+
+  int ret;
+  int opt;
+  struct shv_connection connection;
+  struct shv_node *tree_root;
+  struct shv_con_ctx *ctx;
+  const int comthrd_prio = CONFIG_EXAMPLES_SHV_NXBOOT_UPDATER_PRIORITY - 1;
+
+  const char *user = NULL;
+  const char *passwd = NULL;
+  const char *mount = NULL;
+  const char *ip = NULL;
+  const char *port_s = NULL;
+  int port = 0;
+
+  /* Initialize the communication. But only if parameters are passed. */
+
+  while ((opt = getopt(argc, argv, "hm:i:p:t:u:")) != -1)
+    {
+      switch (opt)
+        {
+          case 'h':
+            print_help(argv[0]);
+            return 0;
+          case 'm':
+            mount = optarg;
+            break;
+          case 'i':
+            ip = optarg;
+            break;
+          case 'p':
+            passwd = optarg;
+            break;
+          case 't':
+            port_s = optarg;
+            port = atoi(port_s);
+            break;
+          case 'u':
+            user = optarg;
+            break;
+          case '?':
+            print_help(argv[0]);
+            return 1;
+        }
+    }
+
+  if (!user || !passwd || !mount || !ip || !port_s)
+    {
+      print_help(argv[0]);
+      return 1;
+    }
+
+  shv_connection_init(&connection, SHV_TLAYER_TCPIP);
+  connection.broker_user =     user;
+  connection.broker_password = passwd;
+  connection.broker_mount =    mount;
+  connection.reconnect_period = 10;
+  connection.reconnect_retries = 0;
+  if (shv_connection_tcpip_init(&connection, ip, port) < 0)
+    {
+      fprintf(stderr, "Have you supplied valid params to shv_connection?\n");
+      return 1;
+    }
+
+  puts("SHV Connection Init OK");
+
+  tree_root = shv_tree_create();
+  if (tree_root == NULL)
+    {
+      fprintf(stderr, "Can't create the SHV tree.");
+      return 1;
+    }
+
+  puts("SHV Tree created!");
+  ctx = shv_com_init(tree_root, &connection, attention_cb);
+  if (ctx == NULL)
+    {
+      fprintf(stderr, "Can't establish the comm with the broker.\n");
+      return 1;
+    }
+
+  ret = shv_create_process_thread(comthrd_prio, ctx);
+  if (ret < 0)
+    {
+      fprintf(stderr, "%s\n", shv_errno_str(ctx));
+      free(ctx);
+      return 1;
+    }
+
+  sem_init(&running, 0, 0);
+  signal(SIGTERM, quit_handler);
+
+  sem_wait(&running);
+
+  puts("Close the communication");
+  shv_com_destroy(ctx);
+  shv_tree_destroy(tree_root);
+
+  return 0;
+}
diff --git a/examples/shv-nxboot-updater/update-script/.gitignore 
b/examples/shv-nxboot-updater/update-script/.gitignore
new file mode 100644
index 000000000..ed8ebf583
--- /dev/null
+++ b/examples/shv-nxboot-updater/update-script/.gitignore
@@ -0,0 +1 @@
+__pycache__
\ No newline at end of file
diff --git a/examples/shv-nxboot-updater/update-script/gui.py 
b/examples/shv-nxboot-updater/update-script/gui.py
new file mode 100755
index 000000000..0298c2c07
--- /dev/null
+++ b/examples/shv-nxboot-updater/update-script/gui.py
@@ -0,0 +1,236 @@
+#!/usr/bin/env python3
+
+############################################################################
+# apps/examples/shv-nxboot-updater/update-script/gui.py
+#
+# 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.
+#
+############################################################################
+
+import argparse
+import asyncio
+import logging
+import sys
+from typing import Any
+
+from PyQt6.QtCore import Qt, QThread
+from PyQt6.QtWidgets import (
+    QApplication,
+    QComboBox,
+    QDialog,
+    QGridLayout,
+    QLabel,
+    QLineEdit,
+    QProgressBar,
+    QPushButton,
+)
+from shvconfirm import shv_confirm
+from shvflasher import shv_flasher
+
+log_levels = (
+    logging.DEBUG,
+    logging.INFO,
+    logging.WARNING,
+    logging.ERROR,
+    logging.CRITICAL,
+)
+
+PROGRESS_STYLE = """
+QProgressBar{
+    border: 2px solid grey;
+    border-radius: 5px;
+    text-align: center
+}
+
+QProgressBar::chunk {
+    background-color: green;
+}
+"""
+
+
+def parse_args() -> argparse.Namespace:
+    """Parse passed arguments and return result."""
+    parser = argparse.ArgumentParser(
+        description="GUI application for NuttX firmware flash over SHV"
+    )
+    parser.add_argument(
+        "-v",
+        action="count",
+        default=0,
+        help="Increase verbosity level of logging",
+    )
+    parser.add_argument(
+        "-q",
+        action="count",
+        default=0,
+        help="Decrease verbosity level of logging",
+    )
+    parser.add_argument(
+        "-i",
+        "--image",
+        dest="image",
+        type=str,
+        default="nuttx.nximg",
+        help="Image path",
+    )
+    parser.add_argument(
+        "-m",
+        "--mount",
+        dest="target_mount",
+        type=str,
+        default="test/nuttxdevice",
+        help="Target mount location on the SHV broker",
+    )
+    parser.add_argument(
+        "-s",
+        "--server",
+        dest="shv_server",
+        type=str,
+        default="tcp://[email protected]:3755?password=xyz",
+        help="SHV server/broker",
+    )
+    return parser.parse_args()
+
+
+async def flashThreadAsync(
+    url: str, img: str, path_to_root, progress_bar: QProgressBar
+) -> None:
+    queue: asyncio.Queue = asyncio.Queue()
+    task = asyncio.create_task(shv_flasher(url, img, path_to_root, queue))
+
+    while True:
+        progressVal = await queue.get()
+        progress_bar.setValue(progressVal)
+
+        if progressVal == 100:
+            break
+
+    await task
+
+
+class flashThread(QThread):
+    def __init__(
+        self,
+        parent: Any,
+        url: str,
+        img: str,
+        path_to_root: str,
+        progress_bar: QProgressBar,
+    ) -> None:
+        QThread.__init__(self, parent)
+        self.url = url
+        self.img = img
+        self.path_to_root = path_to_root
+        self.progress_bar = progress_bar
+
+    def run(self) -> None:
+        asyncio.run(
+            flashThreadAsync(self.url, self.img, self.path_to_root, 
self.progress_bar)
+        )
+
+
+class confirmThread(QThread):
+    def __init__(self, parent: Any, url: str, path_to_root: str) -> None:
+        QThread.__init__(self, parent)
+        self.url = url
+        self.path_to_root = path_to_root
+
+    def run(self) -> None:
+        asyncio.run(shv_confirm(self.url, self.path_to_root))
+
+
+class ShvFlasherGui(QDialog):
+    def __init__(self, image=None, target_mount=None, shv_server=None) -> None:
+        super().__init__()
+        self.setWindowModality(Qt.WindowModality.ApplicationModal)
+        self.setWindowTitle("NuttX Firmware Flasher over SHV")
+
+        lbl_shv_url = QLabel("SHV RCP URL")
+        self.set_interface(shv_server)
+
+        lbl_image = QLabel("Image path")
+        self.image = QLineEdit(image if image is not None else "", self)
+
+        lbl_target_mount = QLabel("Device mount")
+        self.target_mount = QLineEdit(
+            target_mount if target_mount is not None else "", self
+        )
+
+        self.progress_bar = QProgressBar(self)
+        self.progress_bar.setValue(0)
+        self.progress_bar.setStyleSheet(PROGRESS_STYLE)
+
+        pb_flash = QPushButton("FLASH")
+        pb_confirm = QPushButton("CONFIRM")
+        pb_exit = QPushButton("EXIT")
+        grid = QGridLayout()
+
+        grid.addWidget(lbl_shv_url, 0, 0)
+        grid.addWidget(self.interface, 0, 1)
+        grid.addWidget(lbl_image, 1, 0)
+        grid.addWidget(self.image, 1, 1)
+        grid.addWidget(lbl_target_mount, 2, 0)
+        grid.addWidget(self.target_mount, 2, 1)
+        grid.addWidget(self.progress_bar, 3, 0, 1, 3)
+        grid.addWidget(pb_flash, 4, 0)
+        grid.addWidget(pb_confirm, 4, 1)
+        grid.addWidget(pb_exit, 4, 2)
+
+        pb_flash.clicked.connect(self.do_flash)
+        pb_confirm.clicked.connect(self.do_confirm)
+        pb_exit.clicked.connect(self.reject)
+
+        self.setLayout(grid)
+
+    def set_interface(self, shv_server=None) -> None:
+        self.interface = QComboBox()
+        self.interface.setEditable(True)
+        # tcp://user@localhost:3755?password=pass
+        self.interface.addItems([shv_server if shv_server is not None else ""])
+
+    def do_flash(self) -> None:
+        rpc_url = str(self.interface.currentText())
+        img_path = str(self.image.text())
+        path_to_root = str(self.target_mount.text())
+        workerFlash = flashThread(
+            self, rpc_url, img_path, path_to_root, self.progress_bar
+        )
+        workerFlash.start()
+
+    def do_confirm(self) -> None:
+        rpc_url = str(self.interface.currentText())
+        path_to_root = str(self.target_mount.text())
+        worker = confirmThread(self, rpc_url, path_to_root)
+        worker.start()
+
+
+def main() -> None:
+    args = parse_args()
+    logging.basicConfig(
+        level=log_levels[sorted([1 - args.v + args.q, 0, len(log_levels) - 
1])[1]],
+        format="[%(asctime)s] [%(levelname)s] - %(message)s",
+    )
+
+    _ = QApplication(sys.argv)
+
+    dialog = ShvFlasherGui(
+        image=args.image, target_mount=args.target_mount, 
shv_server=args.shv_server
+    )
+    dialog.exec()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/examples/shv-nxboot-updater/update-script/requirements.txt 
b/examples/shv-nxboot-updater/update-script/requirements.txt
new file mode 100644
index 000000000..c3b0be328
--- /dev/null
+++ b/examples/shv-nxboot-updater/update-script/requirements.txt
@@ -0,0 +1,5 @@
+pyshv>=0.10.0
+PyQt6
+argparse
+asyncio
+logging
diff --git a/examples/shv-nxboot-updater/update-script/shvconfirm.py 
b/examples/shv-nxboot-updater/update-script/shvconfirm.py
new file mode 100644
index 000000000..cc9bd06b7
--- /dev/null
+++ b/examples/shv-nxboot-updater/update-script/shvconfirm.py
@@ -0,0 +1,33 @@
+############################################################################
+# apps/examples/shv-nxboot-updater/update-script/shvconfirm.py
+#
+# 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.
+#
+############################################################################
+
+from shv.rpcapi.valueclient import SHVValueClient
+from shv.rpcurl import RpcUrl
+
+
+async def shv_confirm(connection: str, path_to_root: str) -> None:
+    url = RpcUrl.parse(connection)
+    client = await SHVValueClient.connect(url)
+    assert client is not None
+
+    await client.call(f"{path_to_root}/fwStable", "confirm")
+
+    print("FW confirmed.")
+    await client.disconnect()
diff --git a/examples/shv-nxboot-updater/update-script/shvflasher.py 
b/examples/shv-nxboot-updater/update-script/shvflasher.py
new file mode 100644
index 000000000..bb55bdc06
--- /dev/null
+++ b/examples/shv-nxboot-updater/update-script/shvflasher.py
@@ -0,0 +1,85 @@
+############################################################################
+# apps/examples/shv-nxboot-updater/update-script/shvflasher.py
+#
+# 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.
+#
+############################################################################
+
+import asyncio
+import io
+import zlib
+
+from shv import SHVBytes
+from shv.rpcapi.valueclient import SHVValueClient
+from shv.rpcurl import RpcUrl
+
+
+async def shv_flasher(
+    connection: str, name: str, path_to_root: str, queue: asyncio.Queue | None
+) -> None:
+    url = RpcUrl.parse(connection)
+    client = await SHVValueClient.connect(url)
+    assert client is not None
+    node_name = f"{path_to_root}/fwUpdate"
+    node_name_dotdevice = f"{path_to_root}/.device"
+
+    res = await client.call(node_name, "stat")
+
+    maxfilesize = res[1]
+    maxwrite = res[5]
+    print(f"Received maximum enabled write size {maxwrite}.")
+    print(f"Received maximum file size is {maxfilesize}")
+    print(f"Started uploading new firmware {name}... this may take some time.")
+    size = 0
+    with open(name, mode="rb") as f:
+        # first, compute the CRC from the zlib library
+        # turns out, NuttX uses the same polynomial
+
+        if queue:
+            f.seek(0, io.SEEK_END)
+            size = f.tell()
+            print(f"File's size is {size}")
+            f.seek(0, io.SEEK_SET)
+            transfers = size / maxwrite
+
+        i = 0
+        crc = 0
+        while data := f.read(maxwrite):
+            print("Uploading chunk n.", i + 1)
+            crc = zlib.crc32(data, crc)
+            offset = i * maxwrite
+            res = await client.call(node_name, "write", [offset, 
SHVBytes(data)])
+            i += 1
+            if queue:
+                currProgress = (int)((i * 100) / transfers)
+                queue.put_nowait(currProgress)
+
+    print("Flashing completed!")
+
+    # now get the CRC from the device and reset the device, if OK
+    res = await client.call(node_name, "crc", [0, size])
+    # just to be sure, make it unsigned
+    res = res & 0xFFFFFFFF
+    # the result of the CRC is signed, actually, so make reinterpret it as 
unsigned
+    print(f"Calculated CRC: {hex(crc)} and received: {hex(res)}")
+
+    if res == crc:
+        print("Checksum match, perform reset!")
+        res = await client.call(node_name_dotdevice, "reset")
+    else:
+        print("Checksum mismatch!")
+
+    await client.disconnect()
diff --git a/examples/shv-test/Kconfig b/examples/shv-test/Kconfig
new file mode 100644
index 000000000..26532c5dd
--- /dev/null
+++ b/examples/shv-test/Kconfig
@@ -0,0 +1,30 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+menuconfig EXAMPLES_SHV_TEST
+       bool "Silicon Heaven Protocol showcase"
+       depends on NETUTILS_LIBSHVC
+       default n
+       ---help---
+               Enable the shv-test application, to show off the capabilities 
of the SHV protocol.
+
+if EXAMPLES_SHV_TEST
+
+config EXAMPLES_SHV_TEST_PROGNAME
+       string "shv-test App Name"
+       default "shv_test"
+       ---help---
+               This is the name of the program that will be used when the NSH 
ELF
+               program is installed.
+
+config EXAMPLES_SHV_TEST_PRIORITY
+       int "shv-test task priority"
+       default 100
+
+config EXAMPLES_SHV_TEST_STACKSIZE
+       int "shv-test task stack size"
+       default 4096
+
+endif # EXAMPLES_NX_SHV_FWUPDATER
diff --git a/examples/shv-test/Make.defs b/examples/shv-test/Make.defs
new file mode 100644
index 000000000..2a76f7cd9
--- /dev/null
+++ b/examples/shv-test/Make.defs
@@ -0,0 +1,23 @@
+############################################################################
+# apps/examples/shv-test/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_SHV_TEST),)
+CONFIGURED_APPS += $(APPDIR)/examples/shv-test
+endif
diff --git a/examples/shv-test/Makefile b/examples/shv-test/Makefile
new file mode 100644
index 000000000..68a515ad6
--- /dev/null
+++ b/examples/shv-test/Makefile
@@ -0,0 +1,31 @@
+############################################################################
+# apps/examples/shv-test/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
+
+MODULE = $(CONFIG_EXAMPLES_SHV_TEST_UPDATER)
+
+PROGNAME  += $(CONFIG_EXAMPLES_SHV_TEST_PROGNAME)
+PRIORITY  += $(CONFIG_EXAMPLES_SHV_TEST_PRIORITY)
+STACKSIZE += $(CONFIG_EXAMPLES_SHV_TEST_STACKSIZE)
+
+MAINSRC += shv_test.c
+
+include $(APPDIR)/Application.mk
diff --git a/examples/shv-test/shv_test.c b/examples/shv-test/shv_test.c
new file mode 100644
index 000000000..1d2d1acf9
--- /dev/null
+++ b/examples/shv-test/shv_test.c
@@ -0,0 +1,448 @@
+/****************************************************************************
+ * apps/examples/shv-test/shv_test.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <shv/tree/shv_tree.h>
+#include <shv/tree/shv_file_node.h>
+#include <shv/tree/shv_connection.h>
+#include <shv/tree/shv_methods.h>
+#include <shv/tree/shv_clayer_posix.h>
+#include <shv/tree/shv_dotdevice_node.h>
+#include <shv/tree/shv_dotapp_node.h>
+
+#include <nuttx/config.h>
+#include <stdio.h>
+#include <signal.h>
+#include <semaphore.h>
+#include <stdbool.h>
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int shv_nuttxtesting_set(struct shv_con_ctx *shv_ctx,
+                                struct shv_node *item, int rid);
+static int shv_nuttxtesting_get(struct shv_con_ctx *shv_ctx,
+                                struct shv_node *item, int rid);
+static int shv_nuttxtesting_art(struct shv_con_ctx *shv_ctx,
+                                struct shv_node *item, int rid);
+
+static void quit_handler(int signum);
+static void print_help(char *name);
+
+static struct shv_node *shv_tree_create_dynamically(int mode);
+static void attention_cb(struct shv_con_ctx *shv_ctx,
+                         enum shv_attention_reason r);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* An execution barrier */
+
+static sem_t running;
+
+/* Testing variable */
+
+static int g_testing_val;
+
+/* ------------------------- ROOT METHODS --------------------------------- */
+
+static const struct shv_method_des * const shv_dev_root_dmap_items[] =
+{
+  &shv_dmap_item_dir,
+  &shv_dmap_item_ls,
+};
+
+static const struct shv_dmap shv_dev_root_dmap =
+  SHV_CREATE_NODE_DMAP(root, shv_dev_root_dmap_items);
+
+/* ----------------------- nuttxtesting METHODS -------------------------- */
+
+static const struct shv_method_des shv_dev_nuttxtesting_dmap_item_set =
+{
+  .name = "setTestingVal",
+  .method = shv_nuttxtesting_set
+};
+
+static const struct shv_method_des shv_dev_nuttxtesting_dmap_item_get =
+{
+  .name = "getTestingVal",
+  .method = shv_nuttxtesting_get
+};
+
+static const struct shv_method_des shv_dev_nuttxtesting_dmap_item_art =
+{
+  .name = "asciiArt",
+  .method = shv_nuttxtesting_art
+};
+
+static const struct shv_method_des *const shv_dev_nuttxtesting_dmap_items[] =
+{
+  &shv_dev_nuttxtesting_dmap_item_art,
+  &shv_dmap_item_dir,
+  &shv_dev_nuttxtesting_dmap_item_get,
+  &shv_dmap_item_ls,
+  &shv_dev_nuttxtesting_dmap_item_set
+};
+
+static const struct shv_dmap shv_dev_nuttxtesting_dmap =
+  SHV_CREATE_NODE_DMAP(nuttxtesting, shv_dev_nuttxtesting_dmap_items);
+
+/* ------------------- Static const tree root creation ------------------- */
+
+/* First, define all static nodes */
+
+static const struct shv_dotdevice_node shv_static_node_dotdevice =
+{
+  .shv_node =
+  {
+    .name = ".device",
+    .dir = UL_CAST_UNQ1(struct shv_dmap *, &shv_dotdevice_dmap),
+    .children =
+    {
+      .mode = (SHV_NLIST_MODE_GSA | SHV_NLIST_MODE_STATIC)
+    }
+  },
+  .devops =
+  {
+    .reset  = shv_dotdevice_node_posix_reset,
+    .uptime = shv_dotdevice_node_posix_uptime
+  },
+  .name = "SHV Compatible Device",
+  .serial_number = "0xDEADBEEF",
+  .version = "0.1.0"
+};
+
+static const struct shv_dotapp_node shv_static_node_dotapp =
+{
+  .shv_node =
+  {
+    .name = ".app",
+    .dir = UL_CAST_UNQ1(struct shv_dmap *, &shv_dotapp_dmap),
+    .children =
+    {
+      .mode = (SHV_NLIST_MODE_GSA | SHV_NLIST_MODE_STATIC)
+    }
+  },
+  .appops =
+  {
+    .date = NULL /* As of September 25, date parsing not implemented yet */
+  },
+  .name = "NuttX libshvc example",
+  .version = "1.0.0"
+};
+
+static const struct shv_node shv_static_node_nuttxtesting =
+{
+  .name = "nuttxTesting",
+  .dir = UL_CAST_UNQ1(struct shv_dmap *, &shv_dev_nuttxtesting_dmap),
+  .children =
+  {
+    .mode = (SHV_NLIST_MODE_GSA | SHV_NLIST_MODE_STATIC)
+  }
+};
+
+/* Now, define tree root's children */
+
+const struct shv_node *const shv_static_tree_root_items[] =
+{
+  &shv_static_node_dotapp.shv_node,
+  &shv_static_node_dotdevice.shv_node,
+  &shv_static_node_nuttxtesting
+};
+
+/* Construct the root. Yes, it's a bit cumbersome,
+ * but an automated code generator should have no problem with this!
+ */
+
+const struct shv_node shv_static_tree_root =
+{
+  .dir = UL_CAST_UNQ1(struct shv_dmap *, &shv_dev_root_dmap),
+  .children =
+  {
+    .mode = (SHV_NLIST_MODE_GSA | SHV_NLIST_MODE_STATIC),
+    .list =
+    {
+      .gsa =
+      {
+        .root =
+        {
+          .items = (void **)shv_static_tree_root_items,
+          .count = sizeof(shv_static_tree_root_items) /
+                   sizeof(shv_static_tree_root_items[0]),
+          .alloc_count = 0,
+        }
+      }
+    }
+  }
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int shv_nuttxtesting_set(struct shv_con_ctx *shv_ctx,
+                                struct shv_node *item, int rid)
+{
+  shv_unpack_data(&shv_ctx->unpack_ctx, &g_testing_val, 0);
+  printf("Testing val set to %d\n", g_testing_val);
+  shv_send_empty_response(shv_ctx, rid);
+  return 0;
+}
+
+static int shv_nuttxtesting_get(struct shv_con_ctx *shv_ctx,
+                                struct shv_node *item, int rid)
+{
+  shv_unpack_data(&shv_ctx->unpack_ctx, 0, 0);
+  shv_send_int(shv_ctx, rid, g_testing_val);
+  return 0;
+}
+
+static int shv_nuttxtesting_art(struct shv_con_ctx *shv_ctx,
+                                struct shv_node *item, int rid)
+{
+  /* Generated from https://budavariam.github.io/asciiart-text/ */
+
+  shv_unpack_data(&shv_ctx->unpack_ctx, 0, 0);
+  puts("  ____  _   ___     __");
+  puts(" / __ || | | \\ \\   / /");
+  puts(" \\___ \\| |_| |\\ \\ / / ");
+  puts("  ___) |  _  | \\ V /  ");
+  puts(" |____/|_| |_|  \\_/   ");
+  shv_send_int(shv_ctx, rid, 0);
+  return 0;
+}
+
+static struct shv_node *shv_tree_create_dynamically(int mode)
+{
+  struct shv_node           *tree_root;
+  struct shv_dotapp_node    *dotapp_node;
+  struct shv_node           *nuttxtesting_node;
+  struct shv_dotdevice_node *dotdevice_node;
+
+  tree_root = shv_tree_node_new("", &shv_dev_root_dmap, mode);
+  if (tree_root == NULL)
+    {
+      return NULL;
+    }
+
+  dotapp_node = shv_tree_dotapp_node_new(&shv_dotapp_dmap, mode);
+  if (dotapp_node == NULL)
+    {
+      free(tree_root);
+      return NULL;
+    }
+
+  dotapp_node->name = "NuttX libshvc example";
+  dotapp_node->version = "1.0.0";
+
+  shv_tree_add_child(tree_root, &dotapp_node->shv_node);
+
+  dotdevice_node = shv_tree_dotdevice_node_new(&shv_dotdevice_dmap, mode);
+  if (dotdevice_node == NULL)
+    {
+      free(tree_root);
+      free(dotapp_node);
+      return NULL;
+    }
+
+  dotdevice_node->name = "SHV Compatible Device";
+  dotdevice_node->serial_number = "0xDEADBEEF";
+  dotdevice_node->version = "0.1.0";
+  shv_tree_add_child(tree_root, &dotdevice_node->shv_node);
+
+  nuttxtesting_node = shv_tree_node_new("nuttxTesting",
+                                        &shv_dev_nuttxtesting_dmap, mode);
+  if (nuttxtesting_node == NULL)
+    {
+      free(tree_root);
+      free(dotapp_node);
+      free(dotdevice_node);
+      return NULL;
+    }
+
+  shv_tree_add_child(tree_root, nuttxtesting_node);
+
+  return tree_root;
+}
+
+static void quit_handler(int signum)
+{
+  puts("Stopping SHV FW Updater!");
+  sem_post(&running);
+}
+
+static void print_help(char *name)
+{
+  printf("%s: [OPTIONS]\n", name);
+  puts("Silicon Heaven NuttX example");
+  puts("Showcases the tree creation.");
+  puts("Mandatory options:");
+  puts("  -a <0-2>: chooses the tree alloc type:");
+  puts("    0: GAVL");
+  puts("    1: GSA");
+  puts("    2: GSA_STATIC: GSA with .rodata placed nodes");
+  puts("  -m <mount-point>: mount point in the SHV broker");
+  puts("  -i <ip-addr>: IPv4 address of the SHV broker");
+  puts("  -p <passwd>: password to access the SHV broker");
+  puts("  -t <port>: TCP/IP port of the SHV broker");
+  puts("  -u <user>: user to access the SHV broker");
+  puts("Nonmandatory options:");
+  puts("  -h: print help");
+}
+
+static void attention_cb(struct shv_con_ctx *shv_ctx,
+                         enum shv_attention_reason r)
+{
+  if (r == SHV_ATTENTION_ERROR)
+    {
+      printf("Error occurred in SHV, the reason is: %s\n",
+             shv_errno_str(shv_ctx));
+      sem_post(&running);
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: main
+ ****************************************************************************/
+
+int main(int argc, char *argv[])
+{
+  /* Define the SHV Communication parameters */
+
+  int ret;
+  int opt;
+  struct shv_connection connection;
+  const struct shv_node *tree_root;
+  struct shv_con_ctx *ctx;
+  int alloc_mode = SHV_NLIST_MODE_GAVL;
+  const char *user = NULL;
+  const char *passwd = NULL;
+  const char *mount = NULL;
+  const char *ip = NULL;
+  const char *port_s = NULL;
+  int port = 0;
+
+  /* Initialize the communication. But only if parameters are passed. */
+
+  while ((opt = getopt(argc, argv, "a:hm:i:p:t:u:")) != -1)
+    {
+      switch (opt)
+        {
+          case 'a':
+            alloc_mode = atoi(optarg);
+            break;
+          case 'h':
+            print_help(argv[0]);
+            return 0;
+          case 'm':
+            mount = optarg;
+            break;
+          case 'i':
+            ip = optarg;
+            break;
+          case 'p':
+            passwd = optarg;
+            break;
+          case 't':
+            port_s = optarg;
+            port = atoi(port_s);
+            break;
+          case 'u':
+            user = optarg;
+            break;
+          case '?':
+            print_help(argv[0]);
+            return 1;
+        }
+    }
+
+  if (!user || !passwd || !mount || !ip || !port_s)
+    {
+      print_help(argv[0]);
+      return 1;
+    }
+
+  shv_connection_init(&connection, SHV_TLAYER_TCPIP);
+  connection.broker_user =     user;
+  connection.broker_password = passwd;
+  connection.broker_mount =    mount;
+  connection.reconnect_period = 10;
+  connection.reconnect_retries = 0;
+  if (shv_connection_tcpip_init(&connection, ip, port) < 0)
+    {
+      fprintf(stderr, "Have you supplied valid params to shv_connection?\n");
+      return 1;
+    }
+
+  puts("SHV Connection Init OK");
+
+  if (alloc_mode != SHV_NLIST_MODE_STATIC)
+    {
+      tree_root = shv_tree_create_dynamically(alloc_mode);
+      if (tree_root == NULL)
+        {
+          fprintf(stderr, "Can't create the SHV tree.");
+          return 1;
+        }
+    }
+  else
+    {
+      tree_root = &shv_static_tree_root;
+    }
+
+  puts("SHV Tree created!");
+  ctx = shv_com_init((struct shv_node *)tree_root, &connection,
+                     attention_cb);
+  if (ctx == NULL)
+    {
+      fprintf(stderr, "Can't establish the comm with the broker.\n");
+      return 1;
+    }
+
+  ret = shv_create_process_thread(99, ctx);
+  if (ret < 0)
+    {
+      fprintf(stderr, "%s\n", shv_errno_str(ctx));
+      free(ctx);
+      return 1;
+    }
+
+  sem_init(&running, 0, 0);
+  signal(SIGTERM, quit_handler);
+
+  sem_wait(&running);
+
+  puts("Close the communication");
+  shv_com_destroy(ctx);
+  shv_tree_destroy(tree_root);
+
+  return 0;
+}
diff --git a/netutils/libshvc/.gitignore b/netutils/libshvc/.gitignore
new file mode 100644
index 000000000..ee525cabc
--- /dev/null
+++ b/netutils/libshvc/.gitignore
@@ -0,0 +1,2 @@
+shv-libs4c
+*.tar.gz
diff --git a/netutils/libshvc/Kconfig b/netutils/libshvc/Kconfig
new file mode 100644
index 000000000..ba76bc538
--- /dev/null
+++ b/netutils/libshvc/Kconfig
@@ -0,0 +1,11 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config NETUTILS_LIBSHVC
+       bool "Silicon Heaven Protocol (lightweight C implementation)"
+       depends on NETUTILS_LIBULUT
+       default n
+       ---help---
+               Enable the SHV API to be used in NuttX applications.
diff --git a/netutils/libshvc/Make.defs b/netutils/libshvc/Make.defs
new file mode 100644
index 000000000..8b10b8c00
--- /dev/null
+++ b/netutils/libshvc/Make.defs
@@ -0,0 +1,34 @@
+#############################################################################
+# apps/netutils/libshvc/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.
+#
+#############################################################################
+
+ifeq ($(CONFIG_NETUTILS_LIBSHVC),y)
+CONFIGURED_APPS += $(APPDIR)/netutils/libshvc
+
+SHVDIR = shv-libs4c
+REL_PATH_TO_INC = $(SHVDIR)/_compiled/include
+
+# Make <shv/tree/...> and <shv/chainpack/...> visible
+
+CFLAGS   +=  $(INCDIR_PREFIX)$(APPDIR)/netutils/libshvc/$(REL_PATH_TO_INC)
+CXXFLAGS +=  $(INCDIR_PREFIX)$(APPDIR)/netutils/libshvc/$(REL_PATH_TO_INC)
+
+endif
diff --git a/netutils/libshvc/Makefile b/netutils/libshvc/Makefile
new file mode 100644
index 000000000..29fdc071c
--- /dev/null
+++ b/netutils/libshvc/Makefile
@@ -0,0 +1,90 @@
+#############################################################################
+# apps/netutils/libshvc/Makefile
+#
+# 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.
+#
+#############################################################################
+
+include $(APPDIR)/Make.defs
+
+SHVDIR := shv-libs4c
+
+# Commit hash of the supported shv-libs4c revision
+SHV_LIBS4C_COMMIT_HASH := a8aa519a85e503a44b819fe3a4919dccc6fd559a
+
+SHV_LIBS4C_TARGZ := shv-libs4c-$(SHV_LIBS4C_COMMIT_HASH).tar.gz
+
+SHV_LIBS4C_URL := 
https://codeload.github.com/silicon-heaven/shv-libs4c/tar.gz/$(SHV_LIBS4C_COMMIT_HASH)
+
+.PHONY: shv-build-library
+
+define RUN_OMK_MAKE
+$(1):: $(SHVDIR)
+       make -C $(SHVDIR) \
+       CONFIG_SHV_LIBS4C_PLATFORM="nuttx" $(2) \
+       CONFIG_OC_ULUT_INCDIRONLY=y \
+       EXPORT_LIB_OBJS_EARLY=y \
+       CC="$$(CC)" \
+       CXX="$$(CXX)" \
+       CFLAGS="$$(CFLAGS)" \
+       CXXFLAGS="$$(CXXFLAGS)" \
+       LD="$$(LD)" \
+       LDFLAGS="$$(LDFLAGS)" \
+       CONFIG_OC_ULUT_TESTS=n
+endef
+
+define IMPORT_OMK_DEPEND
+
+$(1) : $$(foreach omk_d,$$(wildcard $(1).d),\
+         $$(shell sed -n -e 's/^ \([^\]*\)[\]*$$$$/ \1/p' $$(omk_d)))
+
+endef
+
+ifneq ($(wildcard $(SHVDIR)/_build),)
+-include $(shell true; find $(SHVDIR)/_build -name 'lib*.a.omkvar') # `true' 
is a hack for MinGW
+SHVOBJS = $(sort $(foreach lib,$(static_libs),$($(lib)_objsar)))
+endif
+
+EXTOBJS += $(SHVOBJS)
+
+$(SHVOBJS) : shv-build-library
+
+$(SHV_LIBS4C_TARGZ):
+       @echo "Downloading SHV from $(SHV_LIBS4C_URL)"
+       $(Q) curl -L $(SHV_LIBS4C_URL) -o $(SHV_LIBS4C_TARGZ)
+
+$(SHVDIR): $(SHV_LIBS4C_TARGZ)
+       @echo "Unpacking $(SHV_LIBS4C_TARGZ) -> $(SHVDIR)"
+       $(Q) tar xzf $(SHV_LIBS4C_TARGZ)
+       $(Q) mv shv-libs4c-$(SHV_LIBS4C_COMMIT_HASH) $(SHVDIR)
+       $(Q) touch $(SHVDIR)
+
+$(eval $(call RUN_OMK_MAKE, shv-build-library, library-pass))
+
+$(foreach omk_o,$(SHVOBJS),$(eval $(call IMPORT_OMK_DEPEND,$(omk_o))))
+
+ifeq ($(wildcard $(SHVDIR)/.git),)
+$(eval $(call RUN_OMK_MAKE, context, default-config include-pass))
+
+distclean::
+       make -C $(SHVDIR) distclean
+       $(call DELDIR, $(SHVDIR))
+       $(call DELFILE, $(SHV_LIBS4C_TARGZ))
+endif
+
+include $(APPDIR)/Application.mk
diff --git a/netutils/libulut/.gitignore b/netutils/libulut/.gitignore
new file mode 100644
index 000000000..379c17787
--- /dev/null
+++ b/netutils/libulut/.gitignore
@@ -0,0 +1,2 @@
+ulut
+*.tar.gz
diff --git a/netutils/libulut/Kconfig b/netutils/libulut/Kconfig
new file mode 100644
index 000000000..3f58148b7
--- /dev/null
+++ b/netutils/libulut/Kconfig
@@ -0,0 +1,17 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+# The ulut library is to be meant primarily used with
+# the Silicon Heaven protocol, hence the info comment.
+
+if !NETUTILS_LIBULUT && !NETUTILS_LIBSHVC
+comment "uLan Utilities Library required to support the Silicon Heaven 
protocol"
+endif
+
+config NETUTILS_LIBULUT
+       bool "uLan Utilities Library (ULUT)"
+       default n
+       ---help---
+               Enable the ULUT library to be used in NuttX applications.
diff --git a/netutils/libulut/Make.defs b/netutils/libulut/Make.defs
new file mode 100644
index 000000000..9ea026c0a
--- /dev/null
+++ b/netutils/libulut/Make.defs
@@ -0,0 +1,32 @@
+#############################################################################
+# apps/netutils/libulut/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.
+#
+#############################################################################
+
+ifeq ($(CONFIG_NETUTILS_LIBULUT),y)
+CONFIGURED_APPS += $(APPDIR)/netutils/libulut
+
+ULUTDIT = ulut
+REL_PATH_TO_INC = $(ULUTDIT)/_compiled/include
+
+CFLAGS   +=  $(INCDIR_PREFIX)$(APPDIR)/netutils/libulut/$(REL_PATH_TO_INC)
+CXXFLAGS +=  $(INCDIR_PREFIX)$(APPDIR)/netutils/libulut/$(REL_PATH_TO_INC)
+
+endif
diff --git a/netutils/libulut/Makefile b/netutils/libulut/Makefile
new file mode 100644
index 000000000..d3bdb498f
--- /dev/null
+++ b/netutils/libulut/Makefile
@@ -0,0 +1,90 @@
+#############################################################################
+# apps/netutils/libulut/Makefile
+#
+# 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.
+#
+#############################################################################
+
+include $(APPDIR)/Make.defs
+
+ULUTDIR = ulut
+
+# Commit hash of the supported ulut revision
+ULUT_COMMIT_HASH := c931ea417a8dbfa57888984a956c49f39214d584
+
+ULUT_TARGZ := ulut-$(ULUT_COMMIT_HASH).tar.gz
+
+# Take from Gitlab Mirror
+ULUT_URL := 
https://gitlab.com/pikron/sw-base/ulut/-/archive/$(ULUT_COMMIT_HASH)/$(ULUT_TARGZ)
+
+.PHONY: ulut-build-library
+
+define RUN_OMK_MAKE
+$(1):: $(ULUTDIR)
+       make -C $(ULUTDIR) \
+       CONFIG_OC_ULUT_INCDIRONLY=y \
+       EXPORT_LIB_OBJS_EARLY=y \
+       CC="$$(CC)" \
+       CXX="$$(CXX)" \
+       CFLAGS="$$(CFLAGS)" \
+       CXXFLAGS="$$(CXXFLAGS)" \
+       LD="$$(LD)" \
+       LDFLAGS="$$(LDFLAGS)" \
+       CONFIG_OC_ULUT_TESTS=n
+endef
+
+define IMPORT_OMK_DEPEND
+
+$(1) : $$(foreach omk_d,$$(wildcard $(1).d),\
+         $$(shell sed -n -e 's/^ \([^\]*\)[\]*$$$$/ \1/p' $$(omk_d)))
+
+endef
+
+ifneq ($(wildcard $(ULUTDIR)/_build),)
+-include $(shell true; find $(ULUTDIR)/_build -name 'lib*.a.omkvar') # `true' 
is a hack for MinGW
+ULUTOBJS = $(sort $(foreach lib,$(static_libs),$($(lib)_objsar)))
+endif
+
+EXTOBJS += $(ULUTOBJS)
+
+$(ULUTOBJS) : ulut-build-library
+
+$(ULUT_TARGZ):
+       @echo "Downloading uLut from $(ULUT_URL)"
+       $(Q) curl -L $(ULUT_URL) -o $(ULUT_TARGZ)
+
+$(ULUTDIR): $(ULUT_TARGZ)
+       @echo "Unpacking $(ULUT_TARGZ) -> $(ULUTDIR)"
+       $(Q) tar xzf $(ULUT_TARGZ)
+       $(Q) mv ulut-$(ULUT_COMMIT_HASH) $(ULUTDIR)
+       $(Q) touch $(ULUTDIR)
+
+$(eval $(call RUN_OMK_MAKE, ulut-build-library, library-pass))
+
+$(foreach omk_o,$(ULUTOBJS),$(eval $(call IMPORT_OMK_DEPEND,$(omk_o))))
+
+ifeq ($(wildcard $(ULUTDIR)/.git),)
+$(eval $(call RUN_OMK_MAKE, context, default-config include-pass))
+
+distclean::
+       make -C $(ULUTDIR) distclean
+       $(call DELDIR, $(ULUTDIR))
+       $(call DELFILE, $(ULUT_TARGZ))
+endif
+
+include $(APPDIR)/Application.mk

Reply via email to