diff --git a/examples/shv-nxboot-updater/Kconfig b/examples/shv-nxboot-updater/Kconfig new file mode 100644 index 00000000000..d25da7cd0e4 --- /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 00000000000..745b8622092 --- /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 00000000000..339199a27f3 --- /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 00000000000..0a75cf7275e --- /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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * 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 in the SHV broker"); + puts(" -i : IPv4 address of the SHV broker"); + puts(" -p : password to access the SHV broker"); + puts(" -t : TCP/IP port of the SHV broker"); + puts(" -u : 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 00000000000..ed8ebf583f7 --- /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 00000000000..0298c2c07cc --- /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://xyz@127.0.0.1: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 00000000000..c3b0be328de --- /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 00000000000..cc9bd06b74b --- /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 00000000000..bb55bdc06e9 --- /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 00000000000..26532c5dd51 --- /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 00000000000..2a76f7cd951 --- /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 00000000000..68a515ad647 --- /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 00000000000..1d2d1acf950 --- /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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/**************************************************************************** + * 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 in the SHV broker"); + puts(" -i : IPv4 address of the SHV broker"); + puts(" -p : password to access the SHV broker"); + puts(" -t : TCP/IP port of the SHV broker"); + puts(" -u : 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 00000000000..ee525cabcf0 --- /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 00000000000..ba76bc538e0 --- /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 00000000000..8b10b8c00ed --- /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 and 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 00000000000..29fdc071c33 --- /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 00000000000..379c177875b --- /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 00000000000..3f58148b739 --- /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 00000000000..9ea026c0a15 --- /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 00000000000..d3bdb498fe0 --- /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