From e3d4119b7a70741acc4c5daad0d008cc49351b93 Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Mon, 8 Jul 2019 01:12:44 +0200
Subject: [PATCH] feat(docs): Add sphinx documentation

Signed-off-by: Rahix <rahix@rahix.de>
---
 .gitignore                        |  3 +-
 Documentation/build-docs.sh       |  6 ++
 Documentation/conf.py             | 93 +++++++++++++++++++++++++++++++
 Documentation/epicardium.rst      | 11 ++++
 Documentation/epicardium/api.rst  | 12 ++++
 Documentation/index.rst           | 11 ++++
 Documentation/pycardium.rst       | 13 +++++
 Documentation/pycardium/color.rst | 22 ++++++++
 Documentation/pycardium/leds.rst  | 31 +++++++++++
 epicardium/epicardium.h           | 44 ++++++++++++++-
 pycardium/modules/py/color.py     | 31 +++++++++++
 11 files changed, 273 insertions(+), 4 deletions(-)
 create mode 100755 Documentation/build-docs.sh
 create mode 100644 Documentation/conf.py
 create mode 100644 Documentation/epicardium.rst
 create mode 100644 Documentation/epicardium/api.rst
 create mode 100644 Documentation/index.rst
 create mode 100644 Documentation/pycardium.rst
 create mode 100644 Documentation/pycardium/color.rst
 create mode 100644 Documentation/pycardium/leds.rst

diff --git a/.gitignore b/.gitignore
index c9c7bf9b..c5e16492 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 00000000..09c32eca
--- /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 00000000..3c12ec79
--- /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 00000000..295d69d1
--- /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 00000000..5394eefe
--- /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 00000000..855d3cc0
--- /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 00000000..c51f7d9d
--- /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 00000000..f105394c
--- /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 00000000..17368dde
--- /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 12bb9a1a..e00f7615 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 b072ef97..83d4b5a5 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)
-- 
GitLab