# 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.