summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/design_guide.md196
1 files changed, 196 insertions, 0 deletions
diff --git a/docs/design_guide.md b/docs/design_guide.md
new file mode 100644
index 000000000..970be5291
--- /dev/null
+++ b/docs/design_guide.md
@@ -0,0 +1,196 @@
+# Design Guide
+
+MicroPython has created a great foundation to build upon and to make it even
+better for beginners we've created CircuitPython. This guide covers a number of
+ways the core and libraries are geared towards beginners.
+
+## Start libraries with the cookiecutter
+
+Cookiecutter is a cool tool that lets you bootstrap a new repo based on another
+repo. We've made one [here]() for CircuitPython libraries that include configs
+for Travis CI and ReadTheDocs along with a setup.py, license, code of conduct
+and readme.
+
+```sh
+# The first time
+pip install cookiecutter
+
+cookiecutter gh:adafruit/cookiecutter-adafruit-circuitpython
+```
+
+## Module Naming
+
+Adafruit funded libraries should be under the
+[adafruit organization](https://github.com/adafruit) and have the format
+Adafruit_CircuitPython_<name> and have a corresponding `adafruit_<name>`
+directory (aka package) or `adafruit_<name>.py` file (aka module).
+
+Community created libraries should have the format CircuitPython_<name> and not
+have the `adafruit_` module or package prefix.
+
+Both should have the CircuitPython repository topic on GitHub.
+
+## Lifetime and ContextManagers
+
+A driver should be initialized and ready to use after construction. If the
+device requires deinitialization, then provide it through `deinit()` and also
+provide `__enter__` and `__exit__` to create a context manager usable with `with`.
+
+## Verify your device
+
+Make sure device you are talking to is the device you expect. If not, raise a
+ValueError. Beware that I2C addresses can be identical on different devices so
+read registers you know to make sure they match your expectation. Validating
+this upfront will help catch mistakes.
+
+## Getters/Setters
+
+When designing a driver for a device, use properties for device state and use
+methods for actions that the device performs. Doing this well helps beginners
+understand when to use what. It is also consistent with
+[Python](https://docs.python.org/3/library/functions.html#property).
+
+## Design for compatibility with CPython
+
+CircuitPython is aimed to be one's first experience with code. It will be the
+first step into the world of hardware and software. To ease one's exploration
+out from this first step, make sure that functionality shared with CPython shares
+the same API. It doesn't need to be the full API it can be a subset. However, do
+not add non-CPython APIs to the same modules. Instead, use separate non-CPython
+modules to add extra functionality. By distinguishing API boundaries at modules
+you increase the likelihood that incorrect expectations are found on import and
+not randomly during runtime.
+
+## Document inline
+
+Whenever possible, document your code right next to the code that implements it.
+This makes it more likely to stay up to date with the implementation itself. Use
+Sphinx's automodule to format these all nicely in ReadTheDocs. The cookiecutter
+helps set these up.
+
+Use [rST](http://docutils.sourceforge.net/docs/user/rst/quickref.html) for markup.
+
+### Module description
+
+After the license comment:
+
+```python
+"""
+`<module name>` - <Short description>
+=================================================
+<Longer description.>
+"""
+```
+
+### Class description
+
+```python
+class DS3231:
+ """Interface to the DS3231 RTC."""
+```
+
+### Data descriptor description
+
+Comment is after even though its weird.
+
+```python
+lost_power = i2c_bit.RWBit(0x0f, 7)
+"""True if the device has lost power since the time was set."""
+```
+
+### Property description
+
+```python
+@property
+def datetime(self):
+ """Gets the current date and time or sets the current date and time then starts the clock."""
+ return self.datetime_register
+
+@datetime.setter
+def datetime(self, value):
+ pass
+```
+
+### Method description
+
+```python
+def datetime(self):
+ """Gets the current date and time or sets the current date and time then starts the clock."""
+ return self.datetime_register
+```
+
+## Use BusDevice
+
+BusDevice is an awesome foundational library that manages talking on a shared
+I2C or SPI device for you. Use it to ensure the library can be used in threads
+later.
+
+## Lots of small modules
+
+CircuitPython boards tend to have a small amount of internal flash and a small
+amount of ram but large amounts of external flash for the file system. So, create
+many small libraries that can be loaded as needed instead of one large file that
+does everything.
+
+## Speed second
+
+Speed isn't as important as API clarity and code size. So, prefer simple APIs
+like properties for state even if it sacrifices a bit of speed.
+
+## Avoid allocations in drivers
+
+Although Python doesn't require managing memory, its still a good practice for
+library writers to think about memory allocations. Avoid them in drivers if
+you can because you never know how much something will be called. Fewer
+allocations means less time spent cleaning up. So, where you can, prefer
+bytearray buffers that are created in `__init__` and used throughout the
+object with methods that read or write into the buffer instead of creating new
+objects. `nativeio` classes are design to read and write to subsections of
+buffers.
+
+**However**, this is a memory tradeoff so do not do it for large or rarely used
+buffers.
+
+### Examples
+
+#### ustruct.pack
+Use `ustruct.pack_into` instead of `ustruct.pack`.
+
+## Sensor properties and units
+
+The [Adafruit Unified Sensor Driver Arduino library](https://learn.adafruit.com/using-the-adafruit-unified-sensor-driver/introduction) has a
+[great list](https://learn.adafruit.com/using-the-adafruit-unified-sensor-driver?view=all#standardised-si-units-for-sensor-data)
+of measurements and their units. Use the same ones including the property name
+itself so that drivers can be used interchangeably when they have the same
+properties.
+
+| Property name | Python type | Units |
+|---------------|-------------|-------|
+| `acceleration` | (float, float, float) | x, y, z meter per second per second |
+| `magnetic` | float | micro-Tesla (uT) |
+| `orientation` | (float, float, float) | x, y, z degrees |
+| `gyro` | (float, float, float) | x, y, z radians per second |
+| `temperature` | float | degrees centigrade |
+| `distance` | float | centimeters |
+| `light` | float | SI lux |
+| `pressure` | float | hectopascal (hPa) |
+| `relative_humidity` | float | percent |
+| `current` | float | milliamps (mA) |
+| `voltage` | float | volts (V) |
+| `color` | int | RGB, eight bits per channel (0xff0000 is red) |
+| `alarm` | (time.struct, str) | Sample alarm time and string to characterize frequency ("secondly", "minutely", "hourly", "daily", "weekly", "monthly") |
+| `datetime` | time.struct | date and time |
+
+## Adding native modules
+
+The Python API for a new module should be defined and documented in
+`shared-bindings` and define an underlying C API. If the implementation is
+port-agnostic or relies on underlying APIs of another module, the code should
+live in `shared-module`. If it is port specific then it should live in `common-hal`
+within the port's folder. In either case, the file and folder structure should
+mimic the structure in `shared-bindings`.
+
+## MicroPython compatibility
+
+Keeping compatibility with MicroPython isn't a high priority. It should be done
+when its not in conflict with any of the above goals.