diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 11476d76..375c3e1e 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -38,7 +38,7 @@ env: # The latest CMake available directly with apt is 3.18, but we need >=3.20 # so we fetch that through pip. CMAKE_VERSION: 3.20.5 - DOXYGEN_VERSION: 1.9.6 + DOXYGEN_VERSION: 1.12.0 jobs: doc-build-html: diff --git a/README.md b/README.md index c8a824f1..1f74c32c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Before getting started, make sure you have a proper Zephyr development environme Follow the official [Zephyr Getting Started Guide](https://docs.zephyrproject.org/latest/getting_started/index.html). -### Adding the module as a dependency to an application +### Using the library as a dependency in an application To add this module as a dependency to an application the application's `west.yml` manifest file should be modified in the following way. @@ -39,42 +39,43 @@ Second, a new entry should be added to the projects list: ``` Remember to run `west update` after performing changes to the manifest file. -In addition, an addition to the `Kconfig` file of the application is necessary. +In addition, the Astarte device library `Kconfig` should be added to the `Kconfig` file of the +application. ``` rsource "../../astarte-device-sdk-zephyr/Kconfig" ``` This will add the configuration options of the example module to the application. -### Adding the module as a standalone application +### Using the library as a standalone application -For development or evaluation purposes it can be useful to add this module as a stand alone -application in its own workspace. -This will make it possible to run the module samples without having to set up an additional -application. +For development or evaluation purposes the library can be used as a stand alone application in its +own workspace. +This will make it possible to build and execute the module samples without having to set up an +extra application. #### Creating a new workspace, venv and cloning the example -The first step is to create a new workspace folder and a venv where `west` will reside. -As well as cloning this example repository inside such workspace. +Start by creating a new workspace folder and a venv where `west` will reside. +Then clone this library inside the newly created workspace. ```shell # Create a venv and install the west tool -mkdir ~/zephyr-workspace -python3 -m venv ~/zephyr-workspace/.venv -source ~/zephyr-workspace/.venv/bin/activate +mkdir ~/zephyrproject +python3 -m venv ~/zephyrproject/.venv +source ~/zephyrproject/.venv/bin/activate pip install west # Clone the example application repo -git clone https://github.com/secomind/astarte-device-sdk-zephyr.git ~/zephyr-workspace/astarte-device-sdk-zephyr +git clone https://github.com/secomind/astarte-device-sdk-zephyr.git ~/zephyrproject/astarte-device-sdk-zephyr ``` #### Initializing the workspace -The second step is to initialize the west workspace, using the example repository as the manifest +The west workspace should be then intialized, using the example repository as the manifest repository. ```shell # initialize my-workspace for the example-application (main branch) -cd ~/zephyr-workspace +cd ~/zephyrproject west init -l astarte-device-sdk-zephyr # update Zephyr modules west update @@ -82,12 +83,12 @@ west update #### Exporting zephyr environment and installing python dependencies -Perform some final configuration operations. +Lastly some dependencies will need to be installed for all west extensions to work correctly. ```shell west zephyr-export -pip install -r ~/zephyr-workspace/zephyr/scripts/requirements.txt -pip install -r ~/zephyr-workspace/astarte-device-sdk-zephyr/scripts/requirements.txt +pip install -r ~/zephyrproject/zephyr/scripts/requirements.txt +pip install -r ~/zephyrproject/astarte-device-sdk-zephyr/scripts/requirements.txt ``` #### Fetching binary blobs for ESP32 @@ -116,12 +117,11 @@ Once you have built the application, run the following command to flash it on th west flash ``` -And the following command to run on an emulated board or the native simulator: +Or the following command to run on an emulated board or the native simulator: ```shell west build -t run ``` - #### One time configuration While usually the configuration setting are set in a `prj.conf` file, during development it might @@ -138,11 +138,12 @@ After changing the configuration, the application can be flashed directly using The standard configuration for all the samples include settings for printing the logs through the serial port connected to the host. -#### Unit testing +## Unit testing -To run the unit tests use: +A set of unit test is present under the `tests` directory of this project. +They can be run using twister. ```shell -west twister -c -v --inline-logs -p unit_testing -T ./astarte-device-sdk-zephyr/unittests +west twister -c -T ./astarte-device-sdk-zephyr/tests ``` ## West extension commands @@ -235,7 +236,7 @@ Create the file `./.vscode/settings.json` and fill it with the following content "python.terminal.activateEnvInCurrentTerminal": true, // IntelliSense - "C_Cpp.default.compilerPath": "${userHome}/zephyr-sdk-0.16.3/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc", + "C_Cpp.default.compilerPath": "${userHome}/zephyr-sdk-0.16.8/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc", "C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json", "C_Cpp.autoAddFileAssociations": false, "C_Cpp.debugShortcut": false @@ -249,17 +250,11 @@ for your specific Zephyr SDK installation as versions might change. Also, the compile commands path assumes `west build` gets run from the root of the zephyr workspace. -One more step is required. The python extension does not load at startup when opening VS Code -unless some -[specific activation](https://github.com/microsoft/vscode-python/blob/a5ab3b8c05e84670176aef8fe246ff0164707ac4/package.json#L66-L78) -events happens. -This means that for a zephyr workspace, that by default does not have any of such activation -events, the extension does not load and when opening a terminal the venv does not activate. -To fix this you can create an empty `mspythonconfig.json` file that will serve as an activation -event. However, note that this file might interfere when using Pyright in your project. - ## Architectural documentation Some additional documentation for the library architecture is available. -- [Astarte MQTT client](doc/architecture/astarte_mqtt_client.md) is a soft wrapper around the MQTT - client library from Zephyr. It extends the functionality of the standard MQTT client. +- [Astarte MQTT client](doc/architecture/Astarte-MQTT-client-architecture.md) is a soft wrapper + around the MQTT client library from Zephyr. It extends the functionality of the standard MQTT + client. +- [Astarte device](doc/architecture/Astarte-device-architecture.md) is the main entry point for any + interaction with Astarte. diff --git a/doc/_doxygen/doxygen-awesome-astarte.css b/doc/_doxygen/doxygen-awesome-astarte.css new file mode 100644 index 00000000..732f4b82 --- /dev/null +++ b/doc/_doxygen/doxygen-awesome-astarte.css @@ -0,0 +1,12 @@ +/* + * (C) Copyright 2024, SECO Mind Srl + * + * SPDX-License-Identifier: MIT + */ + +html { + /* side nav width. MUST be = `TREEVIEW_WIDTH`. + * Make sure it is wide enough to contain the page title (logo + title + version) + */ + --side-nav-fixed-width: 400px; +} diff --git a/doc/_doxygen/doxygen-awesome-fragment-copy-button.js b/doc/_doxygen/doxygen-awesome-fragment-copy-button.js new file mode 100644 index 00000000..8f85fb4a --- /dev/null +++ b/doc/_doxygen/doxygen-awesome-fragment-copy-button.js @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2024, SECO Mind Srl + * + * SPDX-License-Identifier: MIT + */ + +class DoxygenAwesomeFragmentCopyButton extends HTMLElement { + constructor() { + super(); + this.onclick=this.copyContent + } + static title = "Copy to clipboard" + static copyIcon = `` + static successIcon = `` + static successDuration = 980 + static init() { + $(function() { + $(document).ready(function() { + if(navigator.clipboard) { + const fragments = document.getElementsByClassName("fragment") + for(const fragment of fragments) { + const fragmentWrapper = document.createElement("div") + fragmentWrapper.className = "doxygen-awesome-fragment-wrapper" + const fragmentCopyButton = document.createElement("doxygen-awesome-fragment-copy-button") + fragmentCopyButton.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon + fragmentCopyButton.title = DoxygenAwesomeFragmentCopyButton.title + + fragment.parentNode.replaceChild(fragmentWrapper, fragment) + fragmentWrapper.appendChild(fragment) + fragmentWrapper.appendChild(fragmentCopyButton) + + } + } + }) + }) + } + + + copyContent() { + const content = this.previousSibling.cloneNode(true) + // filter out line number from file listings + content.querySelectorAll(".lineno, .ttc").forEach((node) => { + node.remove() + }) + let textContent = content.textContent + // remove trailing newlines that appear in file listings + let numberOfTrailingNewlines = 0 + while(textContent.charAt(textContent.length - (numberOfTrailingNewlines + 1)) == '\n') { + numberOfTrailingNewlines++; + } + textContent = textContent.substring(0, textContent.length - numberOfTrailingNewlines) + navigator.clipboard.writeText(textContent); + this.classList.add("success") + this.innerHTML = DoxygenAwesomeFragmentCopyButton.successIcon + window.setTimeout(() => { + this.classList.remove("success") + this.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon + }, DoxygenAwesomeFragmentCopyButton.successDuration); + } +} + +customElements.define("doxygen-awesome-fragment-copy-button", DoxygenAwesomeFragmentCopyButton) diff --git a/doc/_doxygen/doxygen-awesome-interactive-toc.js b/doc/_doxygen/doxygen-awesome-interactive-toc.js new file mode 100644 index 00000000..c1a71d9f --- /dev/null +++ b/doc/_doxygen/doxygen-awesome-interactive-toc.js @@ -0,0 +1,58 @@ +/* + * (C) Copyright 2024, SECO Mind Srl + * + * SPDX-License-Identifier: MIT + */ + +class DoxygenAwesomeInteractiveToc { + static topOffset = 38 + static hideMobileMenu = true + static headers = [] + + static init() { + window.addEventListener("load", () => { + let toc = document.querySelector(".contents > .toc") + if(toc) { + toc.classList.add("interactive") + if(!DoxygenAwesomeInteractiveToc.hideMobileMenu) { + toc.classList.add("open") + } + document.querySelector(".contents > .toc > h3")?.addEventListener("click", () => { + if(toc.classList.contains("open")) { + toc.classList.remove("open") + } else { + toc.classList.add("open") + } + }) + + document.querySelectorAll(".contents > .toc > ul a").forEach((node) => { + let id = node.getAttribute("href").substring(1) + DoxygenAwesomeInteractiveToc.headers.push({ + node: node, + headerNode: document.getElementById(id) + }) + + document.getElementById("doc-content")?.addEventListener("scroll", () => { + DoxygenAwesomeInteractiveToc.update() + }) + }) + DoxygenAwesomeInteractiveToc.update() + } + }) + } + + static update() { + let active = DoxygenAwesomeInteractiveToc.headers[0]?.node + DoxygenAwesomeInteractiveToc.headers.forEach((header) => { + let position = header.headerNode.getBoundingClientRect().top + header.node.classList.remove("active") + header.node.classList.remove("aboveActive") + if(position < DoxygenAwesomeInteractiveToc.topOffset) { + active = header.node + active?.classList.add("aboveActive") + } + }) + active?.classList.add("active") + active?.classList.remove("aboveActive") + } +} diff --git a/doc/_doxygen/doxygen-awesome-paragraph-link.js b/doc/_doxygen/doxygen-awesome-paragraph-link.js new file mode 100644 index 00000000..4125088c --- /dev/null +++ b/doc/_doxygen/doxygen-awesome-paragraph-link.js @@ -0,0 +1,28 @@ +/* + * (C) Copyright 2024, SECO Mind Srl + * + * SPDX-License-Identifier: MIT + */ + +class DoxygenAwesomeParagraphLink { + // Icon from https://fonts.google.com/icons + // Licensed under the Apache 2.0 license: + // https://www.apache.org/licenses/LICENSE-2.0.html + static icon = `` + static title = "Permanent Link" + static init() { + $(function() { + $(document).ready(function() { + document.querySelectorAll(".contents a.anchor[id], .contents .groupheader > a[id]").forEach((node) => { + let anchorlink = document.createElement("a") + anchorlink.setAttribute("href", `#${node.getAttribute("id")}`) + anchorlink.setAttribute("title", DoxygenAwesomeParagraphLink.title) + anchorlink.classList.add("anchorlink") + node.classList.add("anchor") + anchorlink.innerHTML = DoxygenAwesomeParagraphLink.icon + node.parentElement.appendChild(anchorlink) + }) + }) + }) + } +} diff --git a/doc/_doxygen/doxygen-awesome-zephyr.css b/doc/_doxygen/doxygen-awesome-zephyr.css deleted file mode 100644 index 2adbd6ad..00000000 --- a/doc/_doxygen/doxygen-awesome-zephyr.css +++ /dev/null @@ -1,108 +0,0 @@ -/* - * (C) Copyright 2024, SECO Mind Srl - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* This file contains color customizations that follow Zephyr's branding */ - -html { - --primary-color: #af7fe4; - --primary-dark-color: #7929d2; - --primary-light-color: #cb99f6; - --primary-lighter-color: #dfc8fa; - --primary-lightest-color: #efe4fc; - - --side-nav-background: #333f67; - --side-nav-foreground: #c3e3ff; - - --searchbar-background: var(--page-background-color); - --searchbar-foreground: var(--page-foreground-color); - - --link-color: #2980b9; - --param-color: #b71c1c; - - --side-nav-fixed-width: 300px; - --top-height: 220px; -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) { - color-scheme: dark; - - --primary-color: #af7fe4; - --primary-dark-color: #cb99f6; - --primary-light-color: #7929d2; - --primary-lighter-color: #191e21; - --primary-lightest-color: #191a1c; - - --side-nav-background: #252628; - --side-nav-foreground: var(--page-foreground-color); - - --param-color: #ef9a9a; - } -} - -html.dark-mode { - color-scheme: dark; - - --primary-color: #af7fe4; - --primary-dark-color: #cb99f6; - --primary-light-color: #7929d2; - --primary-lighter-color: #191e21; - --primary-lightest-color: #191a1c; - - --side-nav-background: #252628; - --side-nav-foreground: var(--page-foreground-color); - - --param-color: #ef9a9a; -} - -a:link, a:visited, a:hover, a:focus, a:active { - color: var(--link-color) !important; -} - -.paramname { - color: var(--param-color); -} - -dl.section dd, dl.bug dd, dl.deprecated dd { - margin-inline-start: revert; -} - -/* adjust top and title to ~match Sphinx docs */ -#top { - background: var(--side-nav-background); -} - -#titlearea { - padding-bottom: 0; -} - -#titlearea table { - width: 100%; -} - -#projectlogo img { - width: 200px; - height: 95px; - max-height: none !important; - padding-top: 12px; -} - -#projectalign { - display: none; -} - -@media screen and (min-width: 767px) { - #doc-content { - padding-top: calc(var(--top-height) - 180px); - } -} - -/* style for re-injected version */ -#projectversion { - color: var(--side-nav-foreground); - padding-top: 25px; - text-align: center; -} diff --git a/doc/_doxygen/doxygen-awesome-zephyr.js b/doc/_doxygen/doxygen-awesome-zephyr.js deleted file mode 100644 index 4830152f..00000000 --- a/doc/_doxygen/doxygen-awesome-zephyr.js +++ /dev/null @@ -1,13 +0,0 @@ -/* - * (C) Copyright 2024, SECO Mind Srl - * - * SPDX-License-Identifier: Apache-2.0 - */ - -window.addEventListener('DOMContentLoaded', (event) => { - /* re-inject project version at a custom location */ - let version = document.getElementById('projectnumber').innerText - let titleTable = document.querySelector('#titlearea table'); - let cell = titleTable.insertRow(1).insertCell(0); - cell.innerHTML = '