{"id":24300099,"url":"https://github.com/sun-lab-nbb/ataraxis-transport-layer-pc","last_synced_at":"2026-02-07T07:32:45.545Z","repository":{"id":268901267,"uuid":"781137531","full_name":"Sun-Lab-NBB/ataraxis-transport-layer-pc","owner":"Sun-Lab-NBB","description":"A Python library that provides methods for establishing and maintaining bidirectional communication with Arduino and Teensy microcontrollers over USB and UART serial interfaces.","archived":false,"fork":false,"pushed_at":"2025-12-09T18:10:35.000Z","size":795,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-22T12:04:21.700Z","etag":null,"topics":["ataraxis","communcation","serial"],"latest_commit_sha":null,"homepage":"","language":"Python","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-02T20:21:41.000Z","updated_at":"2025-12-09T18:05:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"89d982ff-d569-45fd-91ef-6b2cbdb3a647","html_url":"https://github.com/Sun-Lab-NBB/ataraxis-transport-layer-pc","commit_stats":null,"previous_names":["sun-lab-nbb/ataraxis-transport-layer-pc"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/Sun-Lab-NBB/ataraxis-transport-layer-pc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-transport-layer-pc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-transport-layer-pc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-transport-layer-pc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-transport-layer-pc/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-transport-layer-pc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sun-Lab-NBB%2Fataraxis-transport-layer-pc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29189333,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T05:07:31.176Z","status":"ssl_error","status_checked_at":"2026-02-07T05:06:15.227Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["ataraxis","communcation","serial"],"created_at":"2025-01-16T22:38:51.273Z","updated_at":"2026-02-07T07:32:45.532Z","avatar_url":"https://github.com/Sun-Lab-NBB.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ataraxis-transport-layer-pc\n\nA Python library that provides methods for establishing and maintaining bidirectional communication with Arduino and \nTeensy microcontrollers over USB and UART serial interfaces.\n\n![PyPI - Version](https://img.shields.io/pypi/v/ataraxis-transport-layer-pc)\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ataraxis-transport-layer-pc)\n[![uv](https://tinyurl.com/uvbadge)](https://github.com/astral-sh/uv)\n[![Ruff](https://tinyurl.com/ruffbadge)](https://github.com/astral-sh/ruff)\n![type-checked: mypy](https://img.shields.io/badge/type--checked-mypy-blue?style=flat-square\u0026logo=python)\n![PyPI - License](https://img.shields.io/pypi/l/ataraxis-transport-layer-pc)\n![PyPI - Status](https://img.shields.io/pypi/status/ataraxis-transport-layer-pc)\n![PyPI - Wheel](https://img.shields.io/pypi/wheel/ataraxis-transport-layer-pc)\n\n___\n\n## Detailed Description\n\nThis is the Python implementation of the ataraxis-transport-layer (AXTL) library, designed to run on \nhost-computers (PCs). It provides methods for bidirectionally communicating with microcontrollers running the \n[ataraxis-transport-layer-mc](https://github.com/Sun-Lab-NBB/ataraxis-transport-layer-mc) companion library written in \nC++. The library abstracts all steps necessary to safely send and receive data over the USB and UART communication\ninterfaces. It is specifically designed to support time-critical applications, such as scientific experiments, and can \nachieve microsecond communication speeds for modern microcontroller-PC hardware combinations.\n\n___\n\n## Features\n\n- Supports Windows, Linux, and macOS.\n- Uses Consistent Overhead Byte Stuffing (COBS) to encode payloads during transmission.\n- Supports Circular Redundancy Check (CRC) 8-, 16- and 32-bit polynomials to ensure data integrity during transmission.\n- Allows fine-tuning all library components to support a wide range of application contexts.\n- Uses Just-in-Time (JIT) compilation and NumPy to optimize runtime performance in time-critical applications.\n- Has a [companion](https://github.com/Sun-Lab-NBB/ataraxis-transport-layer-mc) microcontroller libray written in C++.\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\nFor users, all library dependencies are installed automatically by all supported installation methods \n(see the [Installation](#installation) section).\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-transport-layer-pc/releases) that include precompiled \n   binary and source code distribution (sdist) wheels.\n2. If the downloaded distribution is stored as a compressed archive, unpack it using the appropriate decompression tool.\n3. ```cd``` to the root directory of the prepared project distribution.\n4. Run ```python -m pip install .``` to install the project. Alternatively, if using a distribution with precompiled\n   binaries, use ```python -m pip install WHEEL_PATH```, replacing 'WHEEL_PATH' with the path to the wheel file.\n\n### pip\nUse the following command to install the library using pip: ```pip install ataraxis-transport-layer-pc```\n\n___\n\n## Usage\n\n### TransportLayer\nThe TransportLayer class provides the API for bidirectional communication over USB and UART serial interfaces. It \nensures proper encoding and decoding of data packets using the Consistent Overhead Byte Stuffing (COBS) \nscheme and ensures transmitted packet integrity through the use of the Cyclic Redundancy Check (CRC) checksums.\n\n#### Packet Anatomy:\nThe TransportLayer class sends and receives data in the form of packets. Each packet adheres to the following general \nlayout:\n\n`[START] [PAYLOAD SIZE] [COBS OVERHEAD] [PAYLOAD (1 to 254 bytes)] [DELIMITER] [CRC CHECKSUM (1 to 4 bytes)]`\n\nTo optimize runtime efficiency, the class generates two buffers at initialization time that store the incoming and \noutgoing data packets. Additionally, the class generates a static lookup table to speed up the CRC checksum calculations\nat runtime.\n\n***Note!*** TransportLayer’s write_data() and read_data() methods ***exclusively*** work with the **PAYLOAD** region of \neach data buffer. End users can safely ignore all packet-related information and focus on working with transmitted and\nreceived serialized payloads, as it is impossible to access and manipulate packet metadata via the public API.\n\n#### JIT Compilation:\nThe class uses numba under-the-hood to compile many data processing steps to efficient C-code the first time these\nmethods are called. Since compilation is expensive, the first call to each numba-compiled method is typically very slow,\nbut all further calls are considerably faster. For optimal performance, call all TransportLayer methods at least once \nbefore entering the time-critical portion of the runtime so that it has time to precompile the code.\n\n#### Initialization Delay\nSome microcontrollers, such as Arduino AVR boards, reset upon establishing connection over the UART interface. If \nTransportLayer attempts to transmit the data to a microcontroller undergoing the reset, the data may not reach the \nmicrocontroller at all or become corrupted. When using a microcontroller with the UART interface, delay further code \nexecution by ~2–5 seconds after initializing the TransportLayer class to allow the microcontroller to finish its reset \nsequence.\n\n#### Baudrates\nFor microcontrollers using the UART interface, it is essential to set the baudrate to a value supported by the \nmicrocontroller’s hardware. Usually, microcontroller manufacturers provide a list of supported baudrates for each \nmicrocontroller. Additionally, the baudrate values used in the microcontroller and PC versions of the library have to \nmatch. If any of these conditions are not satisfied, the connection can become unstable, leading to the corruption of \nexchanged data packets.\n\n#### Quickstart\nThis minimal example demonstrates how to use this library to send and receive data. It is designed to be used together \nwith the quickstart example of the [companion](https://github.com/Sun-Lab-NBB/ataraxis-transport-layer-mc#quickstart) \nlibrary. See the [rx_tx_loop.py](./examples/rx_tx_loop.py) for the .py implementation of this example:\n```\nfrom dataclasses import field, dataclass\nimport numpy as np\nfrom ataraxis_time import PrecisionTimer\nfrom ataraxis_transport_layer_pc import TransportLayer\nfrom ataraxis_base_utilities import console, LogLevel\n\n# Activates the console to print messages to the terminal during runtime.\nif not console.enabled:\n    console.enable()\n\n# Instantiates a new TransportLayer object. Most class initialization arguments are set to use optimal default values\n# for most microcontrollers and assume that the companion library uses the default parameters. Consult the ReadMe and\n# the API documentation to learn about fine-tuning the TransportLayer's parameters to better match the intended\n# use-case.\ntl_class = TransportLayer(port=\"/dev/ttyACM1\", baudrate=115200, microcontroller_serial_buffer_size=256)\n\n# Note, buffer size 256 is set for an Arduino Due board. Most Arduino boards have buffers capped at 64 or 256\n# bytes. During production runtimes, it is critically important to set the buffer size to the actual size used by the\n# interfaced microcontroller.\n\n# Similarly, the baudrate used here is not optimal for all UART microcontrollers. For the communication to be stable,\n# the baudrate must be set to an optimal value for the specific microcontroller participating in the communication\n# cycle. Use the https://wormfood.net/avrbaudcalc.php tool to find the best baudrate for your AVR board or consult the\n# manufacturer's documentation.\n\n# Pre-creates the objects used for the demonstration below.\ntest_scalar = np.uint32(123456789)\ntest_array = np.zeros(4, dtype=np.uint8)  # [0, 0, 0, 0]\n\n\n# While Python does not have C++-like structures, it has dataclasses that fulfill a similar role.\n@dataclass()  # It is important for the class to NOT be frozen!\nclass TestStruct:\n    test_flag: np.bool = field(default_factory=lambda: np.bool(True))\n    test_float: np.float32 = field(default_factory=lambda: np.float32(6.66))\n\n    def __repr__(self) -\u003e str:\n        return f\"TestStruct(test_flag={self.test_flag}, test_float={round(float(self.test_float), ndigits=2)})\"\n\n\ntest_struct = TestStruct()\n\n# Some Arduino boards reset after receiving a connection request. To make this example universal, sleeps for 2 seconds\n# to ensure the microcontroller is ready to receive data.\ntimer = PrecisionTimer(\"s\")\ntimer.delay(delay=2, allow_sleep=True, block=False)\n\nconsole.echo(\"Transmitting the data to the microcontroller...\")\n\n# Executes one transmission and one data reception cycle. During production runtime, this code would typically run in\n# a function or loop.\n\n# Writes objects to the TransportLayer's transmission buffer, staging them to be sent with the next\n# send_data() command. Note, the objects are written in the order they are read by the microcontroller.\ntl_class.write_data(test_scalar)\ntl_class.write_data(test_array)\ntl_class.write_data(test_struct)\n\n# Packages and sends the contents of the transmission buffer that were written above to the Microcontroller.\ntl_class.send_data()\n\nconsole.echo(\"Data transmission: Complete.\", level=LogLevel.SUCCESS)\n\n# Waits for the microcontroller to receive the data and respond by sending its data back to the PC.\nconsole.echo(\"Waiting for the microcontroller to respond...\")\nwhile not tl_class.available:\n    continue  # If no data is available, the loop blocks until it becomes available.\n\n# If the data is available, carries out the reception procedure (reads the received byte-stream, parses the\n# payload, and makes it available for reading).\ndata_received = tl_class.receive_data()\n\n# If the reception was successful, reads the data, assumed to contain serialized test objects. Note, this\n# example is intended to be used together with the example script from the ataraxis-transport-layer-mc library.\nif data_received:\n    console.echo(\"Data reception: Complete.\", level=LogLevel.SUCCESS)\n\n    # Overwrites the memory of the objects that were sent to the microcontroller with the response data\n    test_scalar = tl_class.read_data(test_scalar)\n    test_array = tl_class.read_data(test_array)\n    test_struct = tl_class.read_data(test_struct)\n\n    # Verifies the received data\n    assert test_scalar == np.uint32(987654321)  # The microcontroller overwrites the scalar with reverse order.\n\n    # The rest of the data is transmitted without any modifications.\n    assert np.array_equal(test_array, np.array([0, 0, 0, 0]))\n    assert test_struct.test_flag == np.bool(True)\n    assert test_struct.test_float == np.float32(6.66)\n\n# Prints the received data values to the terminal for visual inspection.\nconsole.echo(\"Data reading: Complete.\", level=LogLevel.SUCCESS)\nconsole.echo(\"Received data values:\")\nconsole.echo(f\"test_scalar = {test_scalar}\")\nconsole.echo(f\"test_array = {test_array}\")\nconsole.echo(f\"test_struct = {test_struct}\")\n```\n\n#### Key Methods\n\n##### Sending Data\nThere are two key methods associated with sending data to the microcontroller:\n- The `write_data()` method serializes the input object and writes the resultant byte sequence to the \n  transmission buffer’s payload region. Each call appends the data to the end of the payload already stored in the \n  transmission buffer.\n- The `send_data()` method encodes the payload stored in the transmission buffer into a packet using COBS, calculates \n  and adds the CRC checksum to the encoded packet, and transmits the packet to the microcontroller. The method requires \n  at least one byte of data to be written to the staging buffer before it can be sent to the microcontroller.\n\nThe example below showcases the sequence of steps necessary to send the data to the microcontroller and assumes\nTransportLayer 'tl_class' was initialized following the steps in the [Quickstart](#quickstart) example:\n```\n# Generates the test array to simulate the payload.\ntest_array = np.array(object=[1, 2, 3, 0, 0, 6, 0, 8, 0, 0], dtype=np.uint8)\n\n# Writes the data into the instance's transmission buffer. The method raises an error if it is unable to write the \n# data.\ntl_class.write_data(test_array)\n\n# Constructs and hands the packet to the communication interface to be transmitted to the microcontroller.\ntl_class.send_data()\n```\n\n***Note!*** The transmission buffer is reset when the data is transmitted or via the call to the \n`reset_transmission_buffer()` method. Resetting the transmission buffer discards all data stored in the buffer.\n\n#### Receiving Data\nThere are three key methods associated with receiving data from the microcontroller:\n- The `available` property checks if the serial interface has received enough bytes to justify parsing the data.\n- The `receive_data()` method reads the encoded packet from the byte-stream stored in Serial interface buffer, verifies \n  its integrity with the CRC checksum, and decodes the payload from the packet using COBS. If the packet was \n  successfully received and unpacked, this method returns True.\n- The `read_data()` method overwrites the memory (data) of the input object with the data extracted from the received \n  payload. To do so, the method reads and consumes the number of bytes necessary to 'fill' the object with data from \n  the payload. Following this procedure, the object stores the new value(s) that match the read data and the consumed\n  bytes are discarded, meaning it is only possible to read the same data **once**.\n\nThe example below showcases the sequence of steps necessary to receive data from the microcontroller and assumes\nTransportLayer 'tl_class' was initialized following the steps in the [Quickstart](#quickstart) example: \n```\n# Generates the test array to which the received data will be written.\ntest_array[10] = np.array([1, 2, 3, 0, 0, 6, 0, 8, 0, 0], dtype=np.uint8)\n\n# Blocks until the data is received from the microcontroller.\nwhile not tl_class.available:\n    continue\n\n# Parses the received data. Note, this method internally accesses the 'available' property, so it is safe to call \n# receive_data() instead of 'available' in the 'while' loop above without changing how this example behaves.\nreceive_status = tl_class.receive_data()  # Returns True if the packet was received and decoded.\n\n# Recreates and returns the new test_array instance using the data received from the microcontroller. The method raises \n# an error if it is unable to read the data.\nupdated_array = tl_class.read_data(test_array)\n```\n\n***Note!*** Each call to the `receive_data()` method resets the instance’s reception buffer, discarding any potentially\nunprocessed data.\n\n### Discovering Connectable Ports\nTo help determining which USB ports are available for communication, this library exposes the `axtl-ports` CLI command. \nThis command is available from any environment that has the library installed and internally calls the \n`print_available_ports()` standalone function. The command prints all USB ports that can be connected\nby the pySerial interface alongside the available ID information. The returned port address can then be provided to the \nTransportLayer class as the 'port' argument to establish the serial communication through the port.\n\n___\n\n## API Documentation\n\nSee the [API documentation](https://ataraxis-transport-layer-pc-api-docs.netlify.app/) for the\ndetailed description of the 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\n***Note!*** This installation method requires **mamba version 2.3.2 or above**. Currently, all Sun lab automation \npipelines require that mamba is installed through the [miniforge3](https://github.com/conda-forge/miniforge) installer.\n\n1. Download this repository to the local machine using the preferred method, such as git-cloning.\n2. If the downloaded distribution is stored as a compressed archive, unpack it using the appropriate decompression tool.\n3. ```cd``` to the root directory of the prepared project distribution.\n4. Install the core Sun lab development dependencies into the ***base*** mamba environment via the \n   ```mamba install tox uv tox-uv``` command.\n5. Use the ```tox -e create``` command to create the project-specific development environment followed by \n   ```tox -e install``` command to install the project into that environment as a library.\n\n### Additional Dependencies\n\nIn addition to installing the project and all user dependencies, install the following dependencies:\n\n1. [Python](https://www.python.org/downloads/) distributions, one for each version supported by the developed project. \n   Currently, this library supports the three latest stable versions. It is recommended to use a tool like \n   [pyenv](https://github.com/pyenv/pyenv) to install and manage the required versions.\n\n### Development Automation\n\nThis project comes with a fully configured set of automation pipelines implemented using \n[tox](https://tox.wiki/en/latest/user_guide.html). Check the [tox.ini file](tox.ini) for details about the \navailable pipelines and their implementation. Alternatively, call ```tox list``` from the root directory of the project\nto see the list of available tasks.\n\n**Note!** All pull requests for this project have to successfully complete the ```tox``` task before being merged. \nTo expedite the task’s runtime, use the ```tox --parallel``` command to run some tasks in-parallel.\n\n### Automation Troubleshooting\n\nMany packages used in 'tox' automation pipelines (uv, mypy, ruff) and 'tox' itself may experience runtime failures. In \nmost cases, this is related to their caching behavior. If an unintelligible error is encountered with \nany of the automation components, deleting the corresponding .cache (.tox, .ruff_cache, .mypy_cache, etc.) manually \nor via a CLI command typically solves the issue.\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-transport-layer-pc/tags) for the available project \nreleases.\n\n---\n\n## Authors\n\n- Ivan Kondratyev ([Inkaros](https://github.com/Inkaros))\n- Katlynn Ryu ([katlynn-ryu](https://github.com/KatlynnRyu))\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- [PowerBroker2](https://github.com/PowerBroker2) and his \n  [pySerialTransfer](https://github.com/PowerBroker2/pySerialTransfer) for inspiring this library and serving as an \n  example and benchmark. Check pySerialTransfer project as a good alternative to this library with a non-overlapping \n  set of features.\n- The creators of all other dependencies and projects listed in the [pyproject.toml](pyproject.toml) file.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsun-lab-nbb%2Fataraxis-transport-layer-pc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsun-lab-nbb%2Fataraxis-transport-layer-pc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsun-lab-nbb%2Fataraxis-transport-layer-pc/lists"}