{"id":35618752,"url":"https://github.com/sun-lab-nbb/ataraxis-micro-controller","last_synced_at":"2026-01-05T06:02:01.245Z","repository":{"id":319151983,"uuid":"788923878","full_name":"Sun-Lab-NBB/ataraxis-micro-controller","owner":"Sun-Lab-NBB","description":"A C++ library for Arduino and Teensy microcontrollers that provides the framework for integrating custom hardware  modules with a centralized PC control interface.","archived":false,"fork":false,"pushed_at":"2025-10-25T03:03:55.000Z","size":929,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-25T04:23:30.210Z","etag":null,"topics":["arduino","ataraxis","hardware-control","kernel","module","sam-architecture","serial-communication","teensy"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Sun-Lab-NBB.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-19T11:02:31.000Z","updated_at":"2025-10-25T02:59:28.000Z","dependencies_parsed_at":"2025-10-18T08:00:50.784Z","dependency_job_id":"10a7bc12-4957-404a-9f62-a39bed7a8268","html_url":"https://github.com/Sun-Lab-NBB/ataraxis-micro-controller","commit_stats":null,"previous_names":["sun-lab-nbb/ataraxis-micro-controller"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Sun-Lab-NBB/ataraxis-micro-controller","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-micro-controller","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-micro-controller/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-micro-controller/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-micro-controller/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Sun-Lab-NBB","download_url":"https://codeload.github.com/Sun-Lab-NBB/ataraxis-micro-controller/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-micro-controller/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28214407,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2026-01-05T02:00:06.358Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","ataraxis","hardware-control","kernel","module","sam-architecture","serial-communication","teensy"],"created_at":"2026-01-05T06:00:58.884Z","updated_at":"2026-01-05T06:02:01.236Z","avatar_url":"https://github.com/Sun-Lab-NBB.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ataraxis-micro-controller\n\nA C++ library for Arduino and Teensy microcontrollers that provides the framework for integrating custom hardware \nmodules with a centralized PC control interface.\n\n[![PlatformIO Registry](https://tinyurl.com/bdhdc2d8)](https://tinyurl.com/mrj7h9an)\n![c++](https://img.shields.io/badge/C++-00599C?style=flat-square\u0026logo=C%2B%2B\u0026logoColor=white)\n![arduino](https://img.shields.io/badge/Arduino-00878F?logo=arduino\u0026logoColor=fff\u0026style=plastic)\n![license](https://img.shields.io/badge/license-GPLv3-blue)\n\n___\n\n## Detailed Description\n\nThis library allows integrating custom hardware modules of any complexity managed by the Arduino or Teensy \nmicrocontrollers with the [centralized PC interface](https://github.com/Sun-Lab-NBB/ataraxis-communication-interface) \nimplemented in Python. To do so, the library defines a shared API that can be integrated into \nuser-defined modules by subclassing the (base) Module class. It also provides the Kernel class that manages runtime \ntask scheduling, and the Communication class, which handles high-throughput bidirectional communication with the PC.\n\n___\n\n## Features\n\n- Supports all recent Arduino and Teensy architectures and platforms.\n- Provides an easy-to-implement API that integrates any hardware with the centralized host-computer (PC) \n  [interface](https://github.com/Sun-Lab-NBB/ataraxis-communication-interface) written in Python.\n- Abstracts communication and runtime task scheduling, allowing end users to focus on implementing the logic of their \n  custom hardware modules.\n- Supports concurrent command execution for multiple module instances.\n- Contains many sanity checks performed at compile time and initialization to minimize the potential for unexpected\n  behavior and data corruption.\n- GPL 3 License.\n\n___\n\n## Table of Contents\n\n- [Dependencies](#dependencies)\n- [Installation](#installation)\n- [Usage](#usage)\n- [API Documentation](#api-documentation)\n- [Developers](#developers)\n- [Versioning](#versioning)\n- [Authors](#authors)\n- [License](#license)\n- [Acknowledgements](#Acknowledgments)\n\n___\n\n## Dependencies\n\n- An IDE or Framework capable of uploading microcontroller software that supports\n  [Platformio](https://platformio.org/install). This library is explicitly designed to be uploaded via Platformio and\n  will likely not work with any other IDE or Framework.\n\n***Note!*** Developers should see the [Developers](#developers) section for information on installing additional\ndevelopment dependencies.\n\n___\n\n## Installation\n\n### Source\n\nNote, installation from source is ***highly discouraged*** for anyone who is not an active project developer.\n\n1. Download this repository to the local machine using the preferred method, such as git-cloning. Use one of the \n   [stable releases](https://github.com/Sun-Lab-NBB/ataraxis-micro-controller/releases).\n2. Unpack the downloaded tarball and move all 'src' contents into the appropriate destination\n   ('include,' 'src,' or 'libs') directory of the project that needs to use this library.\n3. Add `include \u003ckernel.h\u003e`, `include \u003ccommunication.h\u003e`, and `include \u003cmodule.h\u003e` at the top of the main.cpp file and \n   `include \u003cmodule.h\u003e` at the top of each custom hardware module header file.\n\n### Platformio\n\n1. Navigate to the project’s platformio.ini file and add the following line to the target environment specification:\n   ```lib_deps = inkaros/ataraxis-micro-controller@^2.0.0```.\n2. Add `include \u003ckernel.h\u003e`, `include \u003ccommunication.h\u003e`, and `include \u003cmodule.h\u003e` at the top of the main.cpp file and\n   `include \u003cmodule.h\u003e` at the top of each custom hardware module header file.\n\n___\n\n## Usage\n\n### Quickstart\nThis section demonstrates how to use custom hardware modules compatible with this library. See \n[this section](#implementing-custom-hardware-modules) for instructions on how to implement custom hardware module \nclasses. Note, the example below should be run together with the \n[companion python interface](https://github.com/Sun-Lab-NBB/ataraxis-communication-interface#quickstart) example. See \nthe [module_integration.cpp](./examples/module_integration.cpp) for the .cpp implementation of this example:\n```\n// Dependencies\n#include \"../examples/example_module.h\"  // Since there is an overlap with the general 'examples', uses the local path.\n#include \"Arduino.h\"\n#include \"communication.h\"\n#include \"kernel.h\"\n#include \"module.h\"\n\n// Specifies the unique identifier for the test microcontroller\nconstexpr uint8_t kControllerID = 222;\n\n// Keepalive interval in milliseconds. If the keepalive interval is greater than 0, the Kernel expects the PC to send\n// keepalive messages at that interval. If the Kernel does not receive a keepalive message in time, it assumes that the\n// microcontroller-PC communication has been lost and resets the microcontroller, aborting the runtime.\nconstexpr uint32_t kKeepaliveInterval = 5000;  // Sets the keepalive interval to 5 seconds.\n\n// Initializes the Communication class. This class instance is shared by all other classes and manages incoming and\n// outgoing communication with the companion host-computer (PC). The Communication has to be instantiated first.\n// NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init)\nCommunication axmc_communication(Serial);\n\n// Creates two instances of the TestModule class. The first argument is the module type (family), which is the same (1)\n// for both, the second argument is the module ID (instance), which is different. The type and id codes do not have\n// any inherent meaning, they are defined by the user and are only used to ensure specific module instances can be\n// uniquely addressed during runtime.\nTestModule\u003c\u003e test_module_1(1, 1, axmc_communication);\n\n// Also uses the template to override the digital pin controlled by the module instance from the default (5) to 6.\nTestModule\u003c6\u003e test_module_2(1, 2, axmc_communication);\n\n// Packages all module instances into an array to be managed by the Kernel class.\nModule* modules[] = {\u0026test_module_1, \u0026test_module_2};\n\n// Instantiates the Kernel class. The Kernel has to be instantiated last.\nKernel axmc_kernel(kControllerID, axmc_communication,  modules, kKeepaliveInterval);\n\n// This function is only executed once. Since Kernel manages the setup for each module, there is no need to set up each\n// module's hardware individually.\nvoid setup()\n{\n    // Initializes the serial communication.\n    Serial.begin(115200);\n\n    // Sets up the hardware and software for the Kernel and all managed modules.\n    axmc_kernel.Setup();\n}\n\n// This function is executed repeatedly while the microcontroller is powered.\nvoid loop()\n{\n    // Since the Kernel instance manages the runtime of all modules, the only method that needs to be called\n    // here is the RuntimeCycle method.\n    axmc_kernel.RuntimeCycle();\n}\n```\n\n### User-Defined Variables\nThis library is designed to flexibly support many different use patterns. To do so, it intentionally avoids hardcoding\ncertain metadata variables that allow the PC interface to individuate and address the managed microcontroller and \nspecific hardware module instances. **Each end user has to manually define these values both for the microcontroller \nand the PC.**\n\n- `Controller ID`. This is a unique code from 1 to 255 that identifies the microcontroller. This ID code is used when \n   communicating with the microcontroller and logging the data received from the microcontroller, so \n   **it has to be unique for all microcontrollers and other Ataraxis assets used at the same time.** For example, \n   [Video System](https://github.com/Sun-Lab-NBB/ataraxis-video-system) classes also use the ID code system to \n   identify themselves during communication and logging and **clash** with microcontroller IDs if both are used at the\n   same time.\n\n- `Module Type` for each hardware module instance. This is a unique code from 1 to 255 that identifies the family \n   (class) of each module instance. For example, all solenoid valves may use the type-code '1,' while all voltage \n   sensors may use the type-code '2.' The type-codes do not have any inherent meaning. Their interpretation depends \n   entirely on the end-user’s preference when implementing the hardware module and its PC interface.\n\n- `Module ID` for each hardware module instance. This code has to be unique within the module type (family) and is used \n   to identify specific module instances. For example, if two voltage sensors (type code '2') are used at the same \n   time, the first voltage sensor should use ID code '1,' while the second sensor should use ID code '2.'\n\n### Keepalive\nA major runtime safety feature of this library is the support for keepalive messaging. When enabled, the Kernel instance\nexpects the PC to send a 'keepalive' command at regular intervals, specified by the `keepalive_interval` Kernel \nconstructor argument. If the Kernel does not receive the keepalive message for **two consecutive interval windows**, \nit aborts the runtime by resetting the microcontroller’s hardware and software to the default state and sends an error \nmessage to the PC.\n\nThe keepalive functionality is **disabled** (set to 0) by default, but it is recommended to enable it for most use \ncases. See the [API documentation for the Kernel class](#api-documentation) for more details on configuring the \nkeepalive messaging.\n\n***Note!*** The appropriate keepalive interval depends on the communication speed and the CPU frequency of the \nmicrocontroller. For a fast microcontroller (teensy4.1) that uses the USB communication interface, an appropriate \nkeepalive interval is typically measured in milliseconds (100 to 500). For a slower microcontroller (arduino mega) with \na UART communication interface using the baudrate of 115200, the appropriate keepalive interval is typically measured \nin seconds (2 to 5).\n\n### Custom Hardware Modules\nFor this library, any external hardware that communicates with Arduino or Teensy microcontroller pins is a hardware \nmodule. For example, a 3d-party voltage sensor that emits an analog signal detected by an Arduino microcontroller is a \nmodule. A rotary encoder that sends digital interrupt signals to 3 digital pins of a Teensy microcontroller is a \nmodule. A solenoid valve gated by HIGH signal sent from an Arduino microcontroller’s digital pin is a module.\n\nThe library expects that the logic that governs how the microcontroller interacts with these modules is \nprovided by a C++ class, the 'software' portion of the hardware module. Typically, this class contains the methods for \nmanipulating the hardware module or collecting the data from the hardware module. The central purpose \nof this library is to enable the centralized PC interface, implemented in Python, to work with a wide range of custom \nhardware modules in a standardized fashion. To achieve this, all custom hardware modules have to subclass the base \n[Module](/src/module.h) class, provided by this library. See the section below for details on how to implement \ncompatible hardware modules.\n\n### Implementing Custom Hardware Modules\nAll modules intended to be accessible through this library have to follow the implementation guidelines described in the\n[example module header file](./examples/example_module.h). Specifically, **all custom modules have to subclass the \nModule class from this library and overload all pure virtual methods**. Additionally, it is highly advised to implement \nthe module’s custom command logic using the **stage-based design pattern** shown in the example. Note, all examples \nfeatured in this guide are taken directly from the [example_module.h](./examples/example_module.h) and the \n[module_integration.cpp](./examples/module_integration.cpp).\n\nThe library is intended to be used together with the \n[companion PC interface](https://github.com/Sun-Lab-NBB/ataraxis-communication-interface). **Each custom hardware \nmodule class implemented using this library must have a companion ModuleInterface class implemented in Python.** \nThese two classes act as the endpoints of the PC-Microcontroller interface, while other library assets abstract the \nintermediate steps that connect the PC interface class with the microcontroller hardware logic class.\n\n***Do not directly access the Kernel or Communication classes when implementing custom hardware modules.*** The base \nModule class allows accessing all necessary library assets through the inherited utility methods. See the \n'protected static functions' section of the Module class [API documentation](#api-documentation) for more details about \nthe available utility methods\n\n#### Concurrent (Non-Blocking) Execution\nA major feature of the library is that it allows maximizing the microcontroller’s throughput by partially overlapping \nthe execution of multiple commands under certain conditions. Specifically, it allows executing other commands while \nwaiting for a time-based delay in the currently executed command. This feature is especially relevant for higher-end \nmicrocontrollers, such as Teensy 4.0+, that can execute many instructions during a multi-millisecond delay interval.\n\nDuring each cycle of the microcontroller’s main `loop()` function, the Kernel sequentially instructs each managed module\ninstance to execute its active command. Typically, the module runs through the command, delaying code execution as \nnecessary, and resulting in the microcontroller doing nothing during the delay. With this library, commands can use the \n`WaitForMicros` utility method together with the **stage-based design pattern** showcased by the \n[TestModule’s Pulse command](./examples/example_module.h) to allow other modules to run their commands while the module \nwaits for the delay to expire.\n\n**Warning!** The non-blocking mode is most effective when used with delays that tolerate a degree of imprecision or on \nmicrocontrollers that have a very high CPU clock speed. Additionally, to support non-blocking runtimes, all \nmodules used at the same time must support non-blocking execution for all commands. Overall, the decision of whether to\nuse the non-blocking mode often requires practical testing under the intended runtime conditions and may not be suitable\nfor all use cases.\n\n**Note!** While this library only supports non-blocking execution for time-based delays natively, advanced users can \nfollow the same design principles to implement non-blocking sensor-based delays when implementing custom command logic.\n\n#### Virtual methods\nThese methods provide the inherited API that integrates any custom hardware module with the centralized control \ninterface running on the companion host-computer (PC). Specifically, the Kernel calls these methods during runtime to \ninterface with each managed module instance.\n\n#### SetCustomParameters\nThis method enables the Kernel to unpack and save the module’s runtime parameters, when updated parameter values are \nreceived from the PC. The primary purpose of this virtual method is to tell the Kernel where to unpack the module’s\nparameter data.\n\nFor most use cases, the method can be implemented with a single call to the ExtractParameters() utility method \ninherited from the base Module class:\n```\nbool SetCustomParameters() override\n{\n    return ExtractParameters(parameters);  // Unpacks the received parameter data into the storage object\n}\n```\n\nThe `parameters` object is typically a structure that stores the instance’s PC-addressable runtime parameters. \nThe `ExtractParameters()` utility method, reads the data received from the PC and uses it to overwrite the memory of \nthe provided object.\n\n### RunActiveCommand\nThis method enables the Kernel to execute the managed module’s logic in response to receiving module-addressed commands \nfrom the PC. Specifically, the Kernel receives and queues the commands to be executed and then calls this method for \neach managed module to run the queued command’s logic. The primary purpose of this method is to translate the active \ncommand code into the call to the command’s logic method.\n\nFor most use cases, this method can be implemented with a simple switch statement:\n```\nswitch (static_cast\u003ckCommands\u003e(GetActiveCommand()))\n{\n    // Active command matches the code for the Pulse command\n    case kCommands::kPulse:\n        Pulse();      // Executes the command logic\n        return true;  // Notifies the Kernel that command was recognized and executed\n       \n    // Active command matches the code for the Echo command\n    case kCommands::kEcho: Echo(); return true;\n    \n    // Active command does not match any valid command code\n    default: return false;  // Notifies the Kernel that the command was not recognized\n}\n```\n\nThe switch uses the `GetActiveCommand()` method, inherited from the base Module class, to retrieve the code of the \ncurrently active command. It is recommended to use an enumeration to map valid command codes to meaningful names \naddressable in code, like it is done with the `kCommands` enumeration in the demonstration above. \n\n**Note!** The method ***has*** to return `true` if it recognizes the command and return `false` if it does not. The \nreturned value of this method ***only*** communicates whether the command was recognized. It should ***not*** be used \nto track the runtime status (success / failure) of the called command’s method.\n\n### SetupModule\nThis method enables the Kernel to set up the hardware and software assets for each managed module instance. This is \ndone from the global `setup()` function, which is executed by the Arduino and Teensy microcontrollers after firmware \nreupload. This is also done in response to the PC requesting the controller to be reset to the default state. The \nprimary purpose of this method is to initialize the hardware and software of each module instance to the state that \nsupports the runtime.\n\nThe implementation of this method should follow the same guidelines as the general microcontroller `setup()` function:\n```\nbool SetupModule() override\n{\n    // Configures class hardware\n    pinMode(kPin, OUTPUT);\n    digitalWrite(kPin, LOW);\n\n    // Configures class software\n    parameters.on_duration  = 2000000;\n    parameters.off_duration = 2000000;\n    parameters.echo_value   = 123;\n    \n    // Notifies the Kernel that the setup is complete\n    return true;\n}\n```\n\nIt is recommended to implement the method in a way that always returns `true` and does not fail. However, to support \nthe runtimes that need to be able to fail, the method supports returning `false` to notify the Kernel that the setup has\nfailed. If this method returns `false`, the Kernel deadlocks the microcontroller in the error state until the \nmicrocontroller firmware is reuploaded to fix the setup error.\n\n### Utility Methods\nTo further simplify implementing custom hardware modules, the base Module class exposes a collection of utility methods.\nThese methods provide an easy-to-use API for safely accessing internal attributes and properties of the superclass, \nsimplifying the interaction between the superclass (Module) and the custom logic of each hardware module that inherits \nfrom the base class.\n\nSee the [API Documentation of the base Module class](#api-documentation) for the list of available (protected) Utility\nmethods. Also, see the [TestModule](./examples/example_module.h) for the demonstration on how to use some of these \nmethods when implementing custom hardware module, most notably those relating to sending the data to the PC and using\nthe stage-based command design pattern.\n\n___\n\n## API Documentation\n\nSee the [API documentation](https://ataraxis-micro-controller-api-docs.netlify.app/) for the detailed description of\nthe methods and classes exposed by components of this library.\n\n___\n\n## Developers\n\nThis section provides installation, dependency, and build-system instructions for project developers.\n\n### Installing the Project\n\n1. Install [Platformio](https://platformio.org/install/integration) either as a standalone IDE or as an IDE plugin.\n2. Download this repository to the local machine using the preferred method, such as git-cloning.\n3. If the downloaded distribution is stored as a compressed archive, unpack it using the appropriate decompression tool.\n4. ```cd``` to the root directory of the prepared project distribution.\n5. Run ```pio project init ``` to initialize the project on the local machine. See\n   [Platformio API documentation](https://docs.platformio.org/en/latest/core/userguide/project/cmd_init.html) for\n   more details on initializing and configuring projects with platformio.\n6. If using an IDE that does not natively support platformio integration, call the ```pio project metadata``` command\n   to generate the metadata to integrate the project with the IDE. Note; most mainstream IDEs do not require or benefit\n   from this step.\n\n***Warning!*** To build this library for a platform or architecture that is not explicitly supported, edit the\nplatformio.ini file to include the desired configuration as a separate environment. This project comes preconfigured\nwith support for `teensy 4.1`, `arduino due`, and `arduino mega (R3)` platforms.\n\n### Additional Dependencies\n\nIn addition to installing Platformio and main project dependencies, install the following dependencies:\n\n- [Tox](https://tox.wiki/en/4.15.0/user_guide.html) and [Doxygen](https://www.doxygen.nl/manual/install.html) to build\n  the API documentation for the project. Note; both dependencies have to be available on the local system’s path.\n\n### Development Automation\n\nUnlike other Ataraxis libraries, the automation for this library is primarily provided via the\n[Platformio’s command line interface](https://docs.platformio.org/en/latest/core/userguide/index.html).\nAdditionally, this project uses [tox](https://tox.wiki/en/latest/user_guide.html) for certain automation tasks not\ndirectly covered by platformio, such as API documentation generation. Check the [tox.ini file](tox.ini) for details\nabout the available pipelines and their implementation. Alternatively, call ```tox list``` from the root directory of\nthe project to see the list of available tasks.\n\n**Note!** All pull requests for this project have to successfully complete the `tox`, `pio check`, and `pio test` tasks\nbefore being submitted.\n\n---\n\n## Versioning\n\nThis project uses [semantic versioning](https://semver.org/). See the\n[tags on this repository](https://github.com/Sun-Lab-NBB/ataraxis-micro-controller/tags) for the available project\nreleases.\n\n---\n\n## Authors\n\n- Ivan Kondratyev ([Inkaros](https://github.com/Inkaros))\n- Jasmine Si\n\n---\n\n## License\n\nThis project is licensed under the GPL3 License: see the [LICENSE](LICENSE) file for details.\n\n---\n\n## Acknowledgments\n\n- All Sun lab [members](https://neuroai.github.io/sunlab/people) for providing the inspiration and comments during the\n  development of this library.\n- The creators of all other dependencies and projects listed in the [platformio.ini](platformio.ini) file.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsun-lab-nbb%2Fataraxis-micro-controller","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsun-lab-nbb%2Fataraxis-micro-controller","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsun-lab-nbb%2Fataraxis-micro-controller/lists"}