diff --git a/.gitignore b/.gitignore index c9c7bf9b0b6ce6211d145f7f714a9dec0e807f70..c5e164929f35d24cb36f32831056e50e49745248 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build/ -card10.bin +/Documentation/output/ +__pycache__/ diff --git a/Documentation/build-docs.sh b/Documentation/build-docs.sh new file mode 100755 index 0000000000000000000000000000000000000000..09c32eca4c60f9db830c5ce170752b431064b222 --- /dev/null +++ b/Documentation/build-docs.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e + +cd "$(dirname "$0")" + +sphinx-build -b html . ./output diff --git a/Documentation/conf.py b/Documentation/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..3c12ec794e017e3b001a3c8594653e6af7638022 --- /dev/null +++ b/Documentation/conf.py @@ -0,0 +1,93 @@ +import os +import subprocess +import sys +import time +import sphinx.util.logging + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +sys.path.insert(0, os.path.abspath("../pycardium/modules/py")) + +logger = sphinx.util.logging.getLogger("card10/conf.py") + + +# -- Project information ----------------------------------------------------- + +project = "card10-firmware" +copyright = "2019" + +# The full version, including alpha/beta/rc tags +release = subprocess.check_output( + ["git", "describe", "--long", "--always"] +).decode().strip() +release += "<br />" +release += time.strftime("%F %R") +version = release + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.ifconfig", +] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["output", "Thumbs.db", ".DS_Store"] + +# -- Options for HTML output ------------------------------------------------- {{{ + +# The Read the Docs theme is available from +# - https://github.com/snide/sphinx_rtd_theme +# - https://pypi.python.org/pypi/sphinx_rtd_theme +# - python-sphinx-rtd-theme package (on Debian) +try: + import sphinx_rtd_theme + html_theme = "sphinx_rtd_theme" + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + pygments_style = "monokai" +except ImportError: + logger.warning("The Sphinx \"sphinx_rtd_theme\" HTML theme was not found. Make sure you have the theme installed to produce pretty HTML output. Falling back to the default theme.") + + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["static"] +# }}} + +# -- Options for Auto-Doc ---------------------------------------------------- {{{ +autodoc_mock_imports = [ + "ucollections", + "urandom", + "utime", +] + +autodoc_member_order = "bysource" +# }}} + +# -- Options for Hawkmoth ---------------------------------------------------- {{{ +has_hawkmoth = False +try: + # Attempt importing hawkmoth + import hawkmoth # noqa: F401 + extensions.append("hawkmoth") + + cautodoc_root = os.path.abspath("..") + has_hawkmoth = True +except ImportError: + logger.warning("Hawkmoth was not found. Documentation for Epicardium API will not be generated.") +# }}} + + +# -- Sphinx Setup ------------------------------------------------------------ +def setup(app): + app.add_config_value("has_hawkmoth", has_hawkmoth, "") diff --git a/Documentation/epicardium.rst b/Documentation/epicardium.rst new file mode 100644 index 0000000000000000000000000000000000000000..295d69d1373268e736a12562d7ffdd7ba2b92f1b --- /dev/null +++ b/Documentation/epicardium.rst @@ -0,0 +1,11 @@ +Epicardium +========== + +Epicardium is the main firmware. It runs on core0 and is based on FreeRTOS. +Epicardium provides an API to a payload running on the other core which exposes +most functionality. This section of the docs details this "Epicardium API". + +.. toctree:: + :maxdepth: 1 + + epicardium/api diff --git a/Documentation/epicardium/api.rst b/Documentation/epicardium/api.rst new file mode 100644 index 0000000000000000000000000000000000000000..5394eefeca79e020d779800dd13f657c3d253dad --- /dev/null +++ b/Documentation/epicardium/api.rst @@ -0,0 +1,12 @@ +Epicardium API +============== + +.. ifconfig:: not has_hawkmoth + + .. warning:: + + This version of the documentation was built without + `Hawkmoth <https://github.com/jnikula/hawkmoth>`_ available. This means, + no documentation for the Epicardium API was generated. + +.. c:autodoc:: epicardium/epicardium.h diff --git a/Documentation/index.rst b/Documentation/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..855d3cc01191dc150e11f61c57162a89b2de0bd0 --- /dev/null +++ b/Documentation/index.rst @@ -0,0 +1,11 @@ +card10 firmware docs +==================== + +This is the API documentation for card10's default firmware. + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + epicardium + pycardium diff --git a/Documentation/pycardium.rst b/Documentation/pycardium.rst new file mode 100644 index 0000000000000000000000000000000000000000..c51f7d9de3c733cea1767b4c8df8dc86bd34f4b7 --- /dev/null +++ b/Documentation/pycardium.rst @@ -0,0 +1,13 @@ +Pycardium +========= + +Pycardium is a core1 payload based on MicroPython. It can interface with +card10 using the Epicardium API, which is wrapped in a bunch of python modules. +These modules are documented in this section. + +.. toctree:: + :maxdepth: 1 + :caption: Modules: + + pycardium/color + pycardium/leds diff --git a/Documentation/pycardium/color.rst b/Documentation/pycardium/color.rst new file mode 100644 index 0000000000000000000000000000000000000000..f105394c82cb5db1551c6d5d6b0ee4db7ea90f2f --- /dev/null +++ b/Documentation/pycardium/color.rst @@ -0,0 +1,22 @@ +``color`` - Colors +================== + +Color Class +----------- + +.. automodule:: color + :members: + +Constants +--------- + +The color module also contains a few constanst for commonly used colors: + +.. py:data:: color.BLACK +.. py:data:: color.WHITE +.. py:data:: color.RED +.. py:data:: color.GREEN +.. py:data:: color.YELLOW +.. py:data:: color.BLUE +.. py:data:: color.MAGENTA +.. py:data:: color.CYAN diff --git a/Documentation/pycardium/leds.rst b/Documentation/pycardium/leds.rst new file mode 100644 index 0000000000000000000000000000000000000000..17368dde7baf0face4cc17cb7e7f84aecf364f22 --- /dev/null +++ b/Documentation/pycardium/leds.rst @@ -0,0 +1,31 @@ +``leds`` - LEDs +=============== + +.. py:function:: leds.set(led, color) + + Set one of the card10's RGB LEDs to a certain color:: + + import leds, color + + for i in range(11): + leds.set(i, color.RED) + + :param led: Which led to set. 0-10 are the leds on the top and 11-14 are the 4 "ambient" leds. + :param color: What color to set the led to. Should be a :py:class:`color.Color` but any list/tuple + with 3 elements will work just as well. + +.. py:data:: leds.BOTTOM_RIGHT + + Index of the LED in the bottom right of card10. + +.. py:data:: leds.BOTTOM_LEFT + + Index of the LED in the bottom left of card10. + +.. py:data:: leds.TOP_RIGHT + + Index of the LED in the top right of card10. + +.. py:data:: leds.TOP_LEFT + + Index of the LED in the top left of card10. diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 12bb9a1a9d6fdbd4f3a1d2efa3cc393fa8a3dccd..e00f7615f3ce9209d09d99149b2015a944373bd9 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -6,13 +6,51 @@ #define API(id, def) def #endif -#define API_UART_WRITE 0x1 +/* clang-format off */ +#define API_UART_WRITE 0x1 +#define API_UART_READ 0x2 +#define API_LEDS_SET 0x3 +/* clang-format on */ + +/** + * UART/Serial Interface + * ===================== + */ + +/** + * Write a string to all connected serial devices. This includes: + * + * - Real UART, whose pins are mapped onto USB-C pins. Accessible via the HW-debugger. + * - A CDC-ACM device available via USB. + * - Maybe, in the future, bluetooth serial? + * + * :param str: String to write. Does not necessarily have to be NULL-terminated. + * :param length: Amount of bytes to print. + */ API(API_UART_WRITE, void epic_uart_write_str(const char *str, intptr_t length)); -#define API_UART_READ 0x2 +/** + * Blocking read a single character from any connected serial device. + * ``epic_uart_read_chr`` only returns + * once one byte has been read. + * + * :return: The byte. + */ API(API_UART_READ, char epic_uart_read_chr(void)); -#define API_LEDS_SET 0x3 +/** + * LEDs + * ==== + */ + +/** + * Set one of card10's RGB LEDs to a certain color. + * + * :param led: Which led to set. 0-10 are the leds on the top and 11-14 are the 4 "ambient" leds. + * :param r: Red component of the color. + * :param g: Green component of the color. + * :param b: Blue component of the color. + */ API(API_LEDS_SET, void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)); #endif /* _EPICARDIUM_H */ diff --git a/pycardium/modules/py/color.py b/pycardium/modules/py/color.py index b072ef97f9a33fbd8f3177ccfe8a8f75b2dedd1a..83d4b5a5e1cfaba2eb7737145a5168cec1cc221c 100644 --- a/pycardium/modules/py/color.py +++ b/pycardium/modules/py/color.py @@ -4,8 +4,39 @@ _ColorTuple = ucollections.namedtuple("Color", ["red", "green", "blue"]) class Color(_ColorTuple): + """ + A color in 24-bit RGB. + + You can create a new color from red, green, and blue:: + + yellow = Color(255, 255, 0) + + You can get the HTML representation for a color using:: + + html_repr = str(Color(128, 128, 128)) + assert html_repr == "#808080" + + .. py:attribute:: red + + Red component of this color. + + .. py:attribute:: green + + Green component of this color. + + .. py:attribute:: blue + + Blue component of this color. + """ + @classmethod def from_hex(cls, color): + """ + Create a color from a hexadecimal number:: + + # Magenta + Color.from_hex(0xff00ff) + """ red = (color & 0xff0000) >> 16 green = (color & 0x00ff00) >> 8 blue = (color & 0x0000ff)