Browse Source

Merge pull request #8 from cefn/master

PR now structure and approach somewhat stable
master
Limor "Ladyada" Fried 3 years ago
committed by GitHub
parent
commit
eabc5490cb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 1664 additions and 11 deletions
  1. +2
    -0
      .gitignore
  2. +21
    -0
      .gitmodules
  3. +26
    -4
      README.rst
  4. +69
    -0
      examples/index.md
  5. +61
    -0
      src/adafruit_blinka/__init__.py
  6. +31
    -0
      src/adafruit_blinka/agnostic/__init__.py
  7. +27
    -0
      src/adafruit_blinka/agnostic/time.py
  8. +0
    -0
      src/adafruit_blinka/board/__init__.py
  9. +27
    -0
      src/adafruit_blinka/board/feather_huzzah.py
  10. +29
    -0
      src/adafruit_blinka/board/nodemcu.py
  11. +51
    -0
      src/adafruit_blinka/board/pyboard.py
  12. +0
    -0
      src/adafruit_blinka/microcontroller/__init__.py
  13. +0
    -0
      src/adafruit_blinka/microcontroller/esp8266/__init__.py
  14. +25
    -0
      src/adafruit_blinka/microcontroller/esp8266/pin.py
  15. +0
    -0
      src/adafruit_blinka/microcontroller/stm32/__init__.py
  16. +67
    -0
      src/adafruit_blinka/microcontroller/stm32/pin.py
  17. +80
    -0
      src/bitbangio.py
  18. +17
    -7
      src/board.py
  19. +163
    -0
      src/busio.py
  20. +122
    -0
      src/digitalio.py
  21. +26
    -0
      src/microcontroller/__init__.py
  22. +8
    -0
      src/microcontroller/pin.py
  23. +1
    -0
      test/libraries/bme280
  24. +1
    -0
      test/libraries/bno055
  25. +1
    -0
      test/libraries/bus_device
  26. +1
    -0
      test/libraries/gps
  27. +1
    -0
      test/libraries/mma8451
  28. +1
    -0
      test/libraries/register
  29. +1
    -0
      test/libraries/rfm69
  30. +51
    -0
      test/scripts/upload_feather_huzzah_circuitpython_put.sh
  31. +51
    -0
      test/scripts/upload_feather_huzzah_micropython_put.sh
  32. +46
    -0
      test/scripts/upload_pyboard_micropython_cp.sh
  33. +104
    -0
      test/src/testing/__init__.py
  34. +52
    -0
      test/src/testing/adafruit_blinka.py
  35. +24
    -0
      test/src/testing/board/__init__.py
  36. +7
    -0
      test/src/testing/board/i2c.py
  37. +8
    -0
      test/src/testing/microcontroller/__init__.py
  38. +0
    -0
      test/src/testing/universal/__init__.py
  39. +85
    -0
      test/src/testing/universal/digitalio.py
  40. +92
    -0
      test/src/testing/universal/i2c.py
  41. +14
    -0
      test/src/testing/universal/microcontroller.py
  42. +38
    -0
      test/src/testing/universal/uart.py
  43. +233
    -0
      test/src/unittest.py

+ 2
- 0
.gitignore View File

@ -1,3 +1,5 @@
*.mpy
.idea
__pycache__
_build
*.pyc


+ 21
- 0
.gitmodules View File

@ -0,0 +1,21 @@
[submodule "test/libraries/bme280"]
path = test/libraries/bme280
url = https://github.com/adafruit/Adafruit_CircuitPython_BME280.git
[submodule "test/libraries/gps"]
path = test/libraries/gps
url = https://github.com/adafruit/Adafruit_CircuitPython_GPS.git
[submodule "test/libraries/Adafruit_CircuitPython_RFM69"]
path = test/libraries/rfm69
url = https://github.com/adafruit/Adafruit_CircuitPython_RFM69.git
[submodule "test/libraries/bus_device"]
path = test/libraries/bus_device
url = https://github.com/adafruit/Adafruit_CircuitPython_BusDevice.git
[submodule "test/libraries/bno055"]
path = test/libraries/bno055
url = https://github.com/adafruit/Adafruit_CircuitPython_BNO055.git
[submodule "test/libraries/mma8451"]
path = test/libraries/mma8451
url = https://github.com/adafruit/Adafruit_CircuitPython_MMA8451.git
[submodule "test/libraries/register"]
path = test/libraries/register
url = https://github.com/adafruit/Adafruit_CircuitPython_Register.git

+ 26
- 4
README.rst View File

@ -13,18 +13,40 @@ Introduction
:target: https://travis-ci.org/adafruit/Adafruit__Micropython_Blinka
:alt: Build Status
.. todo:: Describe what the library does.
This repository contains a selection of packages mirroring the CircuitPython API
on hosts running micropython. Working code exists to emulate the CircuitPython packages;
* **board** - breakout-specific pin identities
* **microcontroller** - chip-specific pin identities
* **digitalio** - digital input/output pins, using pin identities from board+microcontroller packages
* **bitbangio** - software-driven interfaces for I2C, SPI
* **busio** - hardware-driven interfaces for I2C, SPI, UART
* **time** * - substitute functions monkey-patched to time module
Dependencies
=============
This driver depends on:
* Micropython
The Micropython compatibility layers described above are intended to provide a CircuitPython-like API for devices which
are running Micropython. Since corresponding packages should be built-in to any standard
CircuitPython image, they have no value on a device already running CircuitPython and would likely conflict in unhappy ways.
The test suites in the test/src folder under **testing.universal** are by design
intended to run on *either* CircuitPython *or* Micropython+compatibility layer to prove conformance.
Usage Example
=============
.. todo:: Add a quick, simple example. It and other examples should live in the examples folder and be included in docs/examples.rst.
At the time of writing (`git:7fc1f8ab <https://github.com/cefn/Adafruit_Micropython_Blinka/tree/7fc1f8ab477124628a5afebbf6826005955805f9>`_),
the following sequence runs through some basic testing of the digitalio compatibility layer...
.. code-block:: python
from testing import test_module_name
test_module_name("testing.universal.digitalio")
An example log from running the suites is `here <https://github.com/cefn/Adafruit_Micropython_Blinka/issues/2#issuecomment-366713394>`_ .
Contributing
============


+ 69
- 0
examples/index.md View File

@ -0,0 +1,69 @@
# About Adafruit_Micropython_Blinka
This repository is structured around integration tests rooted at the `test/src`
directory, intended to test the compatibility layer rooted in `src`.
The tests offer a procedural way to assert equivalence between 'native' CircuitPython behaviour and behaviour of the **adafruit_blinka** compatibility layer.
The structure of the testing modules permits test suites to be imported and configured selectively on different implementations, platforms and boards (see `adafruit_blinka.agnostic.py` for definitions of these terms).
Automated introspection of the python runtime combines with interactive prompts
to configure a scenario for testing (e.g. which platform, which board, what is wired to it)
so the same routines can be carried out on Micropython boards, dual boards running either CircuitPython or Micropython, or dedicated CircuitPython boards.
Typically the tests have first run on a native CircuitPython platform, and are then used to
prove equivalence on a Micropython platform running the **adafruit_blinka** compatibility layer.
# Tests so far
Tests of compatible versions of **digitalio**, **board** and **microcontroller** have successfully demonstrated
the same code running on either platform, setting and getting pin values and using pull.
Tests have also proven compatibility of the following unmodified CircuitPython libraries...
* adafruit_bme280
* adafruit_mma8451
* adafruit_gps
...which proves the fundamentals of bitbangio.I2C, busio.I2C and busio.UART
# Example
To take a minimal example, the following should assert the default behaviour of the DigitalInOut
constructor, checks the behaviour of switch_to_input/output(), configures a pin as a pull-up button, a pull-down button and an LED.
```python
from testing import test_module_name
test_module_name("testing.universal.digitalio")
```
Or to take a more involved example of constructing a test suite requiring hardware,
the following should verify I2C communication with a BME280 module.
```python
import unittest
import testing.universal.i2c
suite = unittest.TestSuite()
suite.addTest(testing.universal.i2c.TestBME280Interactive)
runner = unittest.TestRunner()
runner.run(suite)
```
To prove this on a newly-flashed Feather Huzzah running Micropython 1.9.3,
it should be possible (on a posix-compliant platform with adafruit_ampy installed)
to `cd test/scripts` then run `./upload_feather_huzzah_micropython_put.sh` to
synchronize relevant files to the filesystem of the huzzah, reset the huzzah then
connect using `screen /dev/ttyUSB0 115200` before running the above commands.
Micropython hosts require a micropython repository alongside
the Adafruit_Micropython_Blinka repository. For circuitpython,
the repository is expected to be called circuitpython_2.2.3.
In each case, the matching version should have been checked out from github
and `make` needs to have been run in the `mpy-cross` folder. This provides a tool
to make bytecode-compiled .mpy versions of all .py files before upload so that
tests can be achieved within the limited memory available on many target platforms.
## Comments
There are reference routines in `test/scripts` like `upload_feather_huzzah_micropython_put.sh` which execute a selective bytecode-compile to .mpy format and an ampy upload for CircuitPython/Micropython on esp8266, or `upload_pyboard_micropython_cp.sh` which selectively bytecode-compiles and synchronizes files with cp to the CIRCUITPY or PYBFLASH disk mount for stm32 and samd21 platforms.

+ 61
- 0
src/adafruit_blinka/__init__.py View File

@ -0,0 +1,61 @@
"""Module providing runtime utility objects to support the Micro/CircuitPython api"""
class Enum(object):
"""
Object supporting CircuitPython-style of static symbols
as seen with Direction.OUTPUT, Pull.UP
"""
def __repr__(self):
"""
Assumes instance will be found as attribute of own class.
Returns dot-subscripted path to instance
(assuming absolute import of containing package)
"""
cls = type(self)
for key in dir(cls):
if getattr(cls, key) is self:
return "{}.{}.{}".format(cls.__module__, cls.__qualname__, key)
return repr(self)
@classmethod
def iteritems(cls):
"""
Inspects attributes of the class for instances of the class
and returns as key,value pairs mirroring dict#iteritems
"""
for key in dir(cls):
val = getattr(cls, key)
if type(val) is cls:
yield (key, val)
class ContextManaged:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.deinit()
class Lockable(ContextManaged):
_locked = False
def try_lock(self):
if self._locked:
return False
else:
self._locked = True
return True
def unlock(self):
if self._locked:
self._locked = False
else:
raise ValueError("Not locked")
def patch_system():
import sys
from adafruit_blinka.agnostic import time
sys.modules['time'] = time

+ 31
- 0
src/adafruit_blinka/agnostic/__init__.py View File

@ -0,0 +1,31 @@
"""Allows useful indirection to test Pin naming logic by switching platform in testing
or provide bootstrapping logic for board identification where auto-detection is not
feasible (e.g. multiple ESP8266 boards architecturally identical). Once runtime
environment is established, can choose various routes to make available and re-export
common modules and operations, depending on platform support
"""
import gc
import sys
gc.collect()
try:
microcontroller = sys.platform
except:
microcontroller = None
board = None
if microcontroller is not None:
if microcontroller == "esp8266": # TODO more conservative board-guessing
board = "feather_huzzah"
elif microcontroller == "samd21":
board = "feather_m0_express"
elif microcontroller == "pyboard":
microcontroller = "stm32"
board = "pyboard"
implementation = sys.implementation.name
if implementation == "micropython":
from utime import sleep
elif implementation == "circuitpython":
from time import sleep
gc.collect()

+ 27
- 0
src/adafruit_blinka/agnostic/time.py View File

@ -0,0 +1,27 @@
from adafruit_blinka import agnostic
if agnostic.implementation == "circuitpython":
from time import *
elif agnostic.implementation == "micropython":
import utime
from utime import sleep
from ucollections import namedtuple
_struct_time = namedtuple("struct_time", ("tm_year", "tm_mon", "tm_mday", "tm_hour", "tm_min", "tm_sec", "tm_wday", "tm_yday", "tm_isdst"))
def marshal_time(tm_year, tm_mon, tm_mday, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=-1, tm_yday=-1, tm_isdst=-1):
_struct_time(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)
def struct_time(t):
return marshal_time(*t)
total_ms = 0
prev_ticks_ms = utime.ticks_ms()
def monotonic():
"""
Assumes that monotonic is called more frequently than the wraparound of micropython's utime.ticks_ms()
"""
global prev_ticks_ms, total_ms
ticks_ms = utime.ticks_ms()
total_ms += utime.ticks_diff(ticks_ms, prev_ticks_ms)
prev_ticks_ms = ticks_ms
return total_ms * 0.001

examples/blinka_simpletest.py → src/adafruit_blinka/board/__init__.py View File


+ 27
- 0
src/adafruit_blinka/board/feather_huzzah.py View File

@ -0,0 +1,27 @@
from adafruit_blinka.microcontroller.esp8266 import pin
# TODO need equiv of INPUT_PULL_DOWN_16 ? see https://tttapa.github.io/ESP8266/Chap04%20-%20Microcontroller.html
GPIO0 = pin.GPIO0
GPIO1 = pin.GPIO1
GPIO2 = pin.GPIO2
GPIO3 = pin.GPIO3
GPIO4 = pin.GPIO4
GPIO5 = pin.GPIO5
GPIO12 = pin.GPIO12
GPIO13 = pin.GPIO13
GPIO14 = pin.GPIO14
GPIO15 = pin.GPIO15
GPIO16 = pin.GPIO16
ADC = pin.TOUT
MISO = GPIO12
MOSI = GPIO13
SCK = GPIO14
RX = GPIO3
TX = GPIO1
SDA = GPIO4
SCL = GPIO5

+ 29
- 0
src/adafruit_blinka/board/nodemcu.py View File

@ -0,0 +1,29 @@
from adafruit_blinka.microcontroller.esp8266 import pin
D0 = pin.GPIO16
D1 = pin.GPIO5
D2 = pin.GPIO4
D3 = pin.GPIO0
D4 = pin.GPIO2
D5 = pin.GPIO14
D6 = pin.GPIO12
D7 = pin.GPIO13
D8 = pin.GPIO15
D9 = pin.GPIO3
D10 = pin.GPIO1
TX1 = D4
"""Transmit pin from second (transmit-only) UART """
CLK = D5
"""SPI clock pin"""
MISO = D6
"""SPI MISO (Master in, Slave out)"""
MOSI = D7
"""SPI MOSI (Master out, Slave in)"""
RX0 = D9
TX0 = D10
# GPIO0 and GPIO2 have built-in pull-ups on common ESP8266
# breakout boards making them suitable for I2C SDA and SCL

+ 51
- 0
src/adafruit_blinka/board/pyboard.py View File

@ -0,0 +1,51 @@
from adafruit_blinka.microcontroller.stm32 import pin
X1 = pin.A0
X2 = pin.A1
X3 = pin.A2
X4 = pin.A3
X5 = pin.A4
X6 = pin.A5
X7 = pin.A6
X8 = pin.A7
X9 = pin.B6
X10 = pin.B7
X11 = pin.C4
X12 = pin.C5
X17 = pin.B3
X18 = pin.C13
X19 = pin.C0
X20 = pin.C1
X21 = pin.C2
X22 = pin.C3
Y1 = pin.C6
Y2 = pin.C7
Y3 = pin.B8
Y4 = pin.B9
Y5 = pin.B12
Y6 = pin.B13
Y7 = pin.B14
Y8 = pin.B15
Y9 = pin.B10
Y10 = pin.B11
Y11 = pin.B0
Y12 = pin.B1
SW = pin.B3
LED_RED = pin.A13
LED_GREEN = pin.A14
LED_YELLOW = pin.A15
LED_BLUE = pin.B4
MMA_INT = pin.B2
MMA_AVDD = pin.B5
SD_D0 = pin.C8
SD_D1 = pin.C9
SD_D2 = pin.C10
SD_D3 = pin.C11
SD_CMD = pin.D2
SD_CK = pin.C12
SD = pin.A8
SD_SW = pin.A8
USB_VBUS = pin.A9
USB_ID = pin.A10
USB_DM = pin.A11
USB_DP = pin.A12

+ 0
- 0
src/adafruit_blinka/microcontroller/__init__.py View File


requirements.txt → src/adafruit_blinka/microcontroller/esp8266/__init__.py View File


+ 25
- 0
src/adafruit_blinka/microcontroller/esp8266/pin.py View File

@ -0,0 +1,25 @@
from microcontroller import Pin
GPIO0 = Pin(0)
GPIO1 = Pin(1)
GPIO2 = Pin(2)
GPIO3 = Pin(3)
GPIO4 = Pin(4)
GPIO5 = Pin(5)
GPIO12 = Pin(12)
GPIO13 = Pin(13)
GPIO14 = Pin(14)
GPIO15 = Pin(15)
GPIO16 = Pin(16)
TOUT = Pin("TOUT")
# ordered as spiId, sckId, mosiId, misoId
spiPorts = ((1, GPIO14, GPIO13, GPIO12))
# ordered as uartId, txId, rxId
uartPorts = (
(0, GPIO1, GPIO3),
# (0, GPIO15, GPIO13) # TODO secondary pins for UART0 configurable from Micropython? How to flag?
(1, GPIO2, None))
i2cPorts = ()

+ 0
- 0
src/adafruit_blinka/microcontroller/stm32/__init__.py View File


+ 67
- 0
src/adafruit_blinka/microcontroller/stm32/pin.py View File

@ -0,0 +1,67 @@
from microcontroller import Pin
A0 = Pin('A0')
A1 = Pin('A1')
A2 = Pin('A2')
A3 = Pin('A3')
A4 = Pin('A4')
A5 = Pin('A5')
A6 = Pin('A6')
A7 = Pin('A7')
A8 = Pin('A8')
A9 = Pin('A9')
A10 = Pin('A10')
A11 = Pin('A11')
A12 = Pin('A12')
A13 = Pin('A13')
A14 = Pin('A14')
A15 = Pin('A15')
B0 = Pin('B0')
B1 = Pin('B1')
B2 = Pin('B2')
B3 = Pin('B3')
B4 = Pin('B4')
B5 = Pin('B5')
B6 = Pin('B6')
B7 = Pin('B7')
B8 = Pin('B8')
B9 = Pin('B9')
B10 = Pin('B10')
B11 = Pin('B11')
B12 = Pin('B12')
B13 = Pin('B13')
B14 = Pin('B14')
B15 = Pin('B15')
C0 = Pin('C0')
C1 = Pin('C1')
C2 = Pin('C2')
C3 = Pin('C3')
C4 = Pin('C4')
C5 = Pin('C5')
C6 = Pin('C6')
C7 = Pin('C7')
C8 = Pin('C8')
C9 = Pin('C9')
C10 = Pin('C10')
C11 = Pin('C11')
C12 = Pin('C12')
C13 = Pin('C13')
D2 = Pin('D2')
# ordered as spiId, sckId, mosiId, misoId
spiPorts = ((1, B13, B15, B14), (2, A5, A6, A7))
# ordered as uartId, txId, rxId
uartPorts = (
(1, B6, B7),
(2, A2, A3),
(3, B10, B11),
(4, A0, A1),
(6, C6, C7),
)
i2cPorts = (
(1, B6, B7),
(2, B10, B11),
)

+ 80
- 0
src/bitbangio.py View File

@ -0,0 +1,80 @@
from adafruit_blinka import Lockable, agnostic
class I2C(Lockable):
def __init__(self, scl, sda, frequency=400000):
if agnostic.microcontroller == "stm32":
raise NotImplementedError("No software I2C on {}".format(agnostic.board))
self.init(scl, sda, frequency)
def init(self, scl, sda, frequency):
from machine import Pin
from machine import I2C as _I2C
self.deinit()
id = -1 # force bitbanging implementation - in future introspect platform if SDA/SCL matches hardware I2C
self._i2c = _I2C(id, Pin(scl.id), Pin(sda.id), freq=frequency)
def deinit(self):
try:
del self._i2c
except AttributeError:
pass
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.deinit()
def scan(self):
return self._i2c.scan()
def readfrom_into(self, address, buffer, start=0, end=None):
if start is not 0 or end is not None:
if end is None:
end = len(buffer)
buffer = memoryview(buffer)[start:end]
stop = True # remove for efficiency later
return self._i2c.readfrom_into(address, buffer, stop)
def writeto(self, address, buffer, start=0, end=None, stop=True):
if start is not 0 or end is not None:
if end is None:
return self._i2c.writeto(address, memoryview(buffer)[start:], stop)
else:
return self._i2c.writeto(address, memoryview(buffer)[start:end], stop)
return self._i2c.writeto(address, buffer, stop)
# TODO untested, as actually busio.SPI was on tasklist https://github.com/adafruit/Adafruit_Micropython_Blinka/issues/2 :(
class SPI(Lockable):
def __init__(self, clock, MOSI=None, MISO=None):
from machine import SPI
self._spi = SPI(-1)
self._pins = (clock, MOSI, MISO)
def configure(self, baudrate=100000, polarity=0, phase=0, bits=8):
from machine import SPI,Pin
if self._locked:
# TODO verify if _spi obj 'caches' sck, mosi, miso to avoid storing in _attributeIds (duplicated in busio)
# i.e. #init ignores MOSI=None rather than unsetting
self._spi.init(
baudrate=baudrate,
polarity=polarity,
phase=phase,
bits=bits,
firstbit=SPI.MSB,
sck=Pin(self._pins[0].id),
mosi=Pin(self._pins[1].id),
miso=Pin(self._pins[2].id))
else:
raise RuntimeError("First call try_lock()")
def write(self, buf):
return self._spi.write(buf)
def readinto(self, buf):
return self.readinto(buf)
def write_readinto(self, buffer_out, buffer_in):
return self.write_readinto(buffer_out, buffer_in)

adafruit_blinka.py → src/board.py View File

@ -20,15 +20,25 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_Blinka`
====================================================
.. todo:: Describe what the module does
`board` - Define ids for available pins
=================================================
Conditionally imports and re-exports a submodule, such as boards.esp8266 based on
platform introspection
* Author(s): cefn
"""
# imports
import gc
gc.collect()
from adafruit_blinka.agnostic import board
gc.collect()
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_Micropython_Blinka.git"
if board == "feather_huzzah":
from adafruit_blinka.board.feather_huzzah import *
elif board == "nodemcu":
from adafruit_blinka.board.nodemcu import *
elif board == "pyboard":
from adafruit_blinka.board.pyboard import *
else:
raise NotImplementedError("Board not supported")
gc.collect()

+ 163
- 0
src/busio.py View File

@ -0,0 +1,163 @@
from adafruit_blinka import Enum, Lockable, agnostic
class I2C(Lockable):
def __init__(self, scl, sda, frequency=400000):
self.init(scl, sda, frequency)
def init(self, scl, sda, frequency):
self.deinit()
from machine import I2C as _I2C
from microcontroller.pin import i2cPorts
for portId, portScl, portSda in i2cPorts:
if scl == portScl and sda == portSda:
self._i2c = I2C(portId, mode=_I2C.MASTER, baudrate=frequency)
break
else:
raise NotImplementedError("No Hardware I2C on (scl,sda)={}\nValid UART ports".format(
(scl, sda), i2cPorts))
def deinit(self):
try:
del self._i2c
except AttributeError:
pass
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.deinit()
def scan(self):
return self._i2c.scan()
def readfrom_into(self, address, buffer, start=0, end=None):
if start is not 0 or end is not None:
if end is None:
end = len(buffer)
buffer = memoryview(buffer)[start:end]
stop = True # remove for efficiency later
return self._i2c.readfrom_into(address, buffer, stop)
def writeto(self, address, buffer, start=0, end=None, stop=True):
if start is not 0 or end is not None:
if end is None:
return self._i2c.writeto(address, memoryview(buffer)[start:], stop)
else:
return self._i2c.writeto(address, memoryview(buffer)[start:end], stop)
return self._i2c.writeto(address, buffer, stop)
class SPI(Lockable):
def __init__(self, clock, MOSI=None, MISO=None):
from microcontroller.pin import spiPorts
for portId, portSck, portMosi, portMiso in spiPorts:
if clock == portSck and MOSI == portMosi and MISO == portMiso:
self._spi = SPI(portId)
self._pins = (portSck, portMosi, portMiso)
break
else:
raise NotImplementedError(
"No Hardware SPI on (clock, MOSI, MISO)={}\nValid SPI ports:{}".
format((clock, MOSI, MISO), spiPorts))
def configure(self, baudrate=100000, polarity=0, phase=0, bits=8):
if self._locked:
from machine import Pin
# TODO check if #init ignores MOSI=None rather than unsetting, to save _pinIds attribute
self._spi.init(
baudrate=baudrate,
polarity=polarity,
phase=phase,
bits=bits,
firstbit=SPI.MSB,
sck=Pin(self._pins[0].id),
mosi=Pin(self._pins[1].id),
miso=Pin(self._pins[2].id)
)
else:
raise RuntimeError("First call try_lock()")
def deinit(self):
self._spi = None
self._pinIds = None
def write(self, buf):
return self._spi.write(buf)
def readinto(self, buf):
return self.readinto(buf)
def write_readinto(self, buffer_out, buffer_in):
return self.write_readinto(buffer_out, buffer_in)
class UART(Lockable):
class Parity(Enum):
pass
Parity.ODD = Parity()
Parity.EVEN = Parity()
def __init__(self,
tx,
rx,
baudrate=9600,
bits=8,
parity=None,
stop=1,
timeout=1000,
receiver_buffer_size=64,
flow=None):
from machine import UART as _UART
from microcontroller.pin import uartPorts
self.baudrate = baudrate
if flow is not None: # default 0
raise NotImplementedError(
"Parameter '{}' unsupported on {}".format(
"flow", agnostic.board))
# translate parity flag for Micropython
if parity is UART.Parity.ODD:
parity = 1
elif parity is UART.Parity.EVEN:
parity = 0
elif parity is None:
pass
else:
raise ValueError("Invalid parity")
# check tx and rx have hardware support
for portId, portTx, portRx in uartPorts: #
if portTx == tx and portRx == rx:
self._uart = _UART(
portId,
baudrate,
bits=bits,
parity=parity,
stop=stop,
timeout=timeout,
read_buf_len=receiver_buffer_size
)
break
else:
raise NotImplementedError(
"No Hardware UART on (tx,rx)={}\nValid UART ports".format(
(tx, rx), uartPorts))
def deinit(self):
self._uart = None
def read(self, nbytes=None):
return self._uart.read(nbytes)
def readinto(self, buf, nbytes=None):
return self._uart.readinto(buf, nbytes)
def readline(self):
return self._uart.readline()
def write(self, buf):
return self._uart.write(buf)

+ 122
- 0
src/digitalio.py View File

@ -0,0 +1,122 @@
from machine import Pin
from adafruit_blinka.agnostic import board as boardId
from adafruit_blinka import Enum, ContextManaged
class DriveMode(Enum):
PUSH_PULL = None
OPEN_DRAIN = None
DriveMode.PUSH_PULL = DriveMode()
DriveMode.OPEN_DRAIN = DriveMode()
class Direction(Enum):
INPUT = None
OUTPUT = None
Direction.INPUT = Direction()
Direction.OUTPUT = Direction()
class Pull(Enum):
UP = None
DOWN = None
#NONE=None
Pull.UP = Pull()
Pull.DOWN = Pull()
#Pull.NONE = Pull()
class DigitalInOut(ContextManaged):
_pin = None
def __init__(self, pin):
self._pin = Pin(pin.id)
self.direction = Direction.INPUT
def switch_to_output(self, value=False, drive_mode=DriveMode.PUSH_PULL):
self.direction = Direction.OUTPUT
self.value = value
self.drive_mode = drive_mode
def switch_to_input(self, pull=None):
self.direction = Direction.INPUT
self.pull = pull
def deinit(self):
del self._pin
@property
def direction(self):
return self.__direction
@direction.setter
def direction(self, dir):
self.__direction = dir
if dir is Direction.OUTPUT:
self._pin.init(mode=Pin.OUT)
self.value = False
self.drive_mode = DriveMode.PUSH_PULL
elif dir is Direction.INPUT:
self._pin.init(mode=Pin.IN)
self.pull = None
else:
raise AttributeError("Not a Direction")
@property
def value(self):
return self._pin.value() is 1
@value.setter
def value(self, val):
if self.direction is Direction.OUTPUT:
self._pin.value(1 if val else 0)
else:
raise AttributeError("Not an output")
@property
def pull(self):
if self.direction is Direction.INPUT:
return self.__pull
else:
raise AttributeError("Not an input")
@pull.setter
def pull(self, pul):
if self.direction is Direction.INPUT:
self.__pull = pul
if pul is Pull.UP:
self._pin.init(mode=Pin.IN, pull=Pin.PULL_UP)
elif pul is Pull.DOWN:
if hasattr(Pin, "PULL_DOWN"):
self._pin.init(mode=Pin.IN, pull=Pin.PULL_DOWN)
else:
raise NotImplementedError("{} unsupported on {}".format(
Pull.DOWN, boardId))
elif pul is None:
self._pin.init(mode=Pin.IN, pull=None)
else:
raise AttributeError("Not a Pull")
else:
raise AttributeError("Not an input")
@property
def drive_mode(self):
if self.direction is Direction.OUTPUT:
return self.__drive_mode #
else:
raise AttributeError("Not an output")
@drive_mode.setter
def drive_mode(self, mod):
self.__drive_mode = mod
if mod is DriveMode.OPEN_DRAIN:
self._pin.init(mode=Pin.OPEN_DRAIN)
elif mod is DriveMode.PUSH_PULL:
self._pin.init(mode=Pin.OUT)

+ 26
- 0
src/microcontroller/__init__.py View File

@ -0,0 +1,26 @@
from adafruit_blinka import Enum, agnostic
class Pin(Enum):
def __init__(self, id):
"""Identifier for pin, referencing platform-specific pin id"""
self.id = id
def __repr__(self):
import board
for key in dir(board):
if getattr(board, key) is self:
return "board.{}".format(key)
import microcontroller.pin as pin
for key in dir(pin):
if getattr(pin, key) is self:
return "microcontroller.pin.{}".format(key)
return repr(self)
if agnostic.microcontroller == "esp8266":
from adafruit_blinka.microcontroller.esp8266 import *
elif agnostic.microcontroller == "stm32":
from adafruit_blinka.microcontroller.stm32 import *
else:
raise NotImplementedError("Microcontroller not supported")

+ 8
- 0
src/microcontroller/pin.py View File

@ -0,0 +1,8 @@
from adafruit_blinka import agnostic
if agnostic.microcontroller == "esp8266":
from adafruit_blinka.microcontroller.esp8266.pin import *
elif agnostic.microcontroller == "stm32":
from adafruit_blinka.microcontroller.stm32.pin import *
else:
raise NotImplementedError("Microcontroller not supported")

+ 1
- 0
test/libraries/bme280

@ -0,0 +1 @@
Subproject commit 3219f5ccd5451f1e11a519d9d0d5407237f84d45

+ 1
- 0
test/libraries/bno055

@ -0,0 +1 @@
Subproject commit 978c4c55270c5538dfa84117f426b7ace66ef017

+ 1
- 0
test/libraries/bus_device

@ -0,0 +1 @@
Subproject commit eb7720b0d8dff377e687157e3f052f18a478e4a5

+ 1
- 0
test/libraries/gps

@ -0,0 +1 @@
Subproject commit cd71268274f6a025ff2d944e0e1781b7435dd426

+ 1
- 0
test/libraries/mma8451

@ -0,0 +1 @@
Subproject commit f389f1f57f5567a8e23901346f264285f432a061

+ 1
- 0
test/libraries/register

@ -0,0 +1 @@
Subproject commit f86b4549c1f8ec10682cb5e5148693dc29c85602

+ 1
- 0
test/libraries/rfm69

@ -0,0 +1 @@
Subproject commit 1abb4f7ce6fa5513c4e9c7dc280c1c2c28a7d062

+ 51
- 0
test/scripts/upload_feather_huzzah_circuitpython_put.sh View File

@ -0,0 +1,51 @@
#!/bin/sh
PORT=/dev/ttyUSB0
export MPYCROSS=`realpath ../../../circuitpython_2.2.3/mpy-cross/mpy-cross`
# switch to test sources
cd ../src
# create test source directories on board
find testing -type d | \
grep -v -E "(^./.git.*|^./.idea|^./.vscode|__pycache__)" | \
xargs -n1 -I {} sh -c "echo Creating directory {} ...; ampy --port ${PORT} mkdir --exists-okay {}"
# compile source .py files to .mpy
find . -type f -name '*.py' | \
xargs -n1 -I {} sh -c "echo compiling {} ...; ${MPYCROSS} {}"
# upload bytecode .mpy files
find . -type f -name '*.mpy' | \
xargs -n1 -I {} sh -c "echo uploading {} ...; ampy --port ${PORT} put {} {}"
#switch to test libraries
cd ../libraries/
# Compile adafruit libraries to bytecode and upload
for SUBMODULE in `find . -mindepth 1 -maxdepth 1 -type d `
do
cd ${SUBMODULE}
# create adafruit library directories on board
find . -mindepth 1 -type d | \
grep -v -E "(^./.git.*|__pycache__|^./doc.*|^./example.*)" | \
xargs -n1 -I {} sh -c "echo Creating directory {} ...; ampy --port ${PORT} mkdir --exists-okay {}"
# compile adafruit library .py files to .mpy
find . -type f -name '*.py' | \
grep -v -E "(^./conf.py|^./docs/conf.py|^./setup.py|^./example.*)" | \
xargs -n1 -I {} sh -c "echo compiling {} ...; ${MPYCROSS} {}"
# upload adafruit library .mpy files
find . -type f -name '*.mpy' | \
xargs -n1 -I {} sh -c "echo uploading {} ...; ampy --port ${PORT} put {} {}"
cd ../
done
# switch to adafruit_blinka source
cd ../../src
# create adafruit_blinka agnostic package for cross-platform logic
ampy --port $PORT mkdir --exists-okay adafruit_blinka
ampy --port $PORT mkdir --exists-okay adafruit_blinka/agnostic
# upload agnostic.mpy for platform detection
$MPYCROSS adafruit_blinka/agnostic/__init__.py
ampy --port $PORT put adafruit_blinka/agnostic/__init__.mpy adafruit_blinka/agnostic/__init__.mpy
# upload time.mpy for time logic
$MPYCROSS adafruit_blinka/agnostic/time.py
ampy --port $PORT put adafruit_blinka/agnostic/time.mpy adafruit_blinka/agnostic/time.mpy

+ 51
- 0
test/scripts/upload_feather_huzzah_micropython_put.sh View File

@ -0,0 +1,51 @@
#!/bin/sh
PORT=/dev/ttyUSB0
export MPYCROSS=`realpath ../../../micropython/mpy-cross/mpy-cross`
# switch to test sources
cd ../src
# create test source directories on board
find testing -type d | \
grep -v -E "(^./.git.*|^./.idea|^./.vscode|__pycache__)" | \
xargs -n1 -I {} sh -c "echo Creating directory {} ...; ampy --port ${PORT} mkdir --exists-okay {}"
# compile source .py files to .mpy
find . -type f -name '*.py' | \
xargs -n1 -I {} sh -c "echo compiling {} ...; ${MPYCROSS} {}"
# upload bytecode .mpy files
find . -type f -name '*.mpy' | \
xargs -n1 -I {} sh -c "echo uploading {} ...; ampy --port ${PORT} put {} {}"
#switch to test libraries
cd ../libraries/
# Compile adafruit libraries to bytecode and upload
for SUBMODULE in `find . -mindepth 1 -maxdepth 1 -type d `
do
cd ${SUBMODULE}
# create adafruit library directories on board
find . -mindepth 1 -type d | \
grep -v -E "(^./.git.*|__pycache__|^./doc.*|^./example.*)" | \
xargs -n1 -I {} sh -c "echo Creating directory {} ...; ampy --port ${PORT} mkdir --exists-okay {}"
# compile adafruit library .py files to .mpy
find . -type f -name '*.py' | \
grep -v -E "(^./conf.py|^./docs/conf.py|^./setup.py|^./example.*)" | \
xargs -n1 -I {} sh -c "echo compiling {} ...; ${MPYCROSS} {}"
# upload adafruit library .mpy files
find . -type f -name '*.mpy' | \
xargs -n1 -I {} sh -c "echo uploading {} ...; ampy --port ${PORT} put {} {}"
cd ../
done
# switch to adafruit_blinka source
cd ../../src
find . -mindepth 1 -type d | \
grep -v -E "(^./.git.*|__pycache__)" | \
xargs -n1 -I {} sh -c "echo Creating directory {} ...; ampy --port ${PORT} mkdir --exists-okay {}"
# compile adafruit blinka .py files to .mpy
find . -type f -name '*.py' | \
xargs -n1 -I {} sh -c "echo compiling {} ...; ${MPYCROSS} {}"
# upload adafruit blinka .mpy files
find . -type f -name '*.mpy' | \
xargs -n1 -I {} sh -c "echo uploading {} ...; ampy --port ${PORT} put {} {}"

+ 46
- 0
test/scripts/upload_pyboard_micropython_cp.sh View File

@ -0,0 +1,46 @@
#!/bin/sh
export PORT="/dev/ttyUSB0"
export MPYCROSS=`realpath ../../../micropython/mpy-cross/mpy-cross`
export COPY="cp --parents "
export ROOT="/media/cefn/PYBFLASH/"
# switch to test sources
cd ../src
# compile source .py files to .mpy
find . -type f -name '*.py' | \
xargs -n1 -I {} sh -c "echo compiling {} ...; ${MPYCROSS} {}"
# upload bytecode .mpy files
find ./ -type f -name '*.mpy' | \
sed "s|^\./||" | \
xargs -n1 -I {} sh -c "echo uploading {} ...; ${COPY} {} ${ROOT}"
#switch to test libraries
cd ../libraries/
# Compile adafruit libraries to bytecode and upload
for SUBMODULE in gps # `find . -mindepth 1 -maxdepth 1 -type d `
do
cd ${SUBMODULE}
# compile adafruit library .py files to .mpy
find . -type f -name '*.py' | \
grep -v -E "(^./conf.py|^./docs/conf.py|^./setup.py|^./example.*)" | \
xargs -n1 -I {} sh -c "echo compiling {} ...; ${MPYCROSS} {}"
# upload adafruit library .mpy files
find ./ -type f -name '*.mpy' | \
sed "s|^\./||" | \
xargs -n1 -I {} sh -c "echo uploading {} ...; ${COPY} {} ${ROOT}"
cd ../
done
# switch to adafruit_blinka source
cd ../../src
# compile adafruit blinka .py files to .mpy
find . -type f -name '*.py' | \
xargs -n1 -I {} sh -c "echo compiling {} ...; ${MPYCROSS} {}"
# upload adafruit blinka .mpy files
find ./ -type f -name '*.mpy' | \
sed "s|^\./||" | \
xargs -n1 -I {} sh -c "echo uploading {} ...; ${COPY} {} ${ROOT}"

+ 104
- 0
test/src/testing/__init__.py View File

@ -0,0 +1,104 @@
# mitigate heap fragmentation issues by pre-loading major libraries
import gc
gc.collect()
import unittest
gc.collect()
def yes_no(q, default=True):
a = input(q + " (Y/n)?" if default else " (y/N)?")
a=a.lower()
if a == '':
return default
elif a == "n":
a = False
elif a == "y":
a = True
return a
def multi_choice(q, choices, defaultPos=None):
if defaultPos is not None:
print("{} [{}]?".format(q, defaultPos))
else:
print(q + "?")
for pos, choice in enumerate(choices):
print("{}) {}".format(pos, choice))
a = input()
a=a.lower()
try:
if a == '':
a = defaultPos
else:
a = int(a)
return choices[a]
except Exception as e:
print(e)
return None
def await_true(name, fun, interval=0, patience=60):
from adafruit_blinka.agnostic.time import sleep, monotonic
print("Waiting {} sec until {} (CTRL+C give up)".format(patience, name))
deadline = monotonic() + patience
try:
while deadline - monotonic() > 0:
if fun():
return True
else:
sleep(interval)
return False
except KeyboardInterrupt:
return False
def test_module(module, runner=None):
import unittest
if runner is None:
runner = unittest.TestRunner()
suite = unittest.TestSuite()
for key in dir(module):
val = getattr(module, key)
try:
if issubclass(val, unittest.TestCase):
suite.addTest(val)
except:
pass
return runner.run(suite)
def test_module_name(absolute, runner=None):
try:
print("Suite begin: {}".format(absolute))
module=__import__(absolute)
relatives = absolute.split(".")
if len(relatives) > 1:
for relative in relatives[1:]:
module = getattr(module, relative)
return test_module(module, runner)
finally:
print("Suite end: {}".format(absolute))
def test_interactive(*module_names):
for module_name in module_names:
if yes_no("Run suite {}".format(module_name)):
gc.collect()
test_module_name(module_name)
def test_prepare(casetype):
case = casetype()
case.setUp()
def main():
"""
moduleNames = ["testing.implementation.universal.digitalio",]
if agnostic.implementation == "micropython":
moduleNames.extend([ "testing.implementation.micropython.digitalio",])
"""
moduleNames = ["testing.implementation.universal.bitbangio"]
unittest.raiseException = True # terminates with stack information on userspace Exception
unittest.raiseBaseException = True # terminates with stack information on system Exception
test_interactive(*moduleNames)
gc.collect()

+ 52
- 0
test/src/testing/adafruit_blinka.py View File

@ -0,0 +1,52 @@
import unittest
class TestEnum(unittest.TestCase):
"""
Verifies the repl() and str() behaviour of an example Enum
Enums represent configuration values such as digitalio.Direction, digitalio.Pull etc.
"""
def setUp(self):
"""Create an example Enum, mocking __module__ and __qualname__"""
import adafruit_blinka
class Cls(adafruit_blinka.Enum):
pass
Cls.one = Cls()
Cls.two = Cls()
# class refs would be implicitly populated correctly in a real module
Cls.__module__ = "ho.hum"
Cls.__qualname__ = "Example"
self.Cls = Cls
def test_iteritems(self):
"""A subtype of Enum can list all attributes of its own type"""
items = list(self.Cls.iteritems())
self.assertEqual( items, [("one",self.Cls.one),("two",self.Cls.two),])
def test_repr(self):
"""A repr() call on an Enum gives its fully-qualified name"""
name = "one"
actual = repr(getattr(self.Cls, name))
expected = "{}.{}.{}".format(self.Cls.__module__, self.Cls.__qualname__, name)
self.assertEqual( actual, expected)
def test_str(self):
"""A str() call on an Enum performs the same as repr()"""
self.assertEqual(str(self.Cls.one), repr(self.Cls.one))
class TestDigitalInOut(unittest.TestCase):
def test_context_manager(self):
import digitalio
from testing.board import default_pin
"""Deinitialisation is triggered by __exit__() and should dispose machine.pin reference"""
dio = digitalio.DigitalInOut(default_pin)
self.assertIsNotNone(dio._pin)
with dio:
pass
self.assertIsNone(dio._pin)

+ 24
- 0
test/src/testing/board/__init__.py View File

@ -0,0 +1,24 @@
"""Configuration of testing fixtures depending on the board layout"""
from adafruit_blinka import agnostic
import board
if agnostic.board == "feather_m0_express":
default_pin = board.D5
led_pin = board.D13
led_hardwired = True
led_inverted = False
elif agnostic.board == "feather_huzzah":
default_pin = board.GPIO4
led_pin = board.GPIO0 # red led
led_hardwired = True
led_inverted = True
elif agnostic.board == "pyboard":
default_pin = board.X1
led_pin = board.LED_BLUE
led_hardwired = True
led_inverted = False
uartTxId = "B6"
uartRXId = "B7"
else:
raise NotImplementedError("Board not supported")

+ 7
- 0
test/src/testing/board/i2c.py View File

@ -0,0 +1,7 @@
from adafruit_blinka import agnostic
if agnostic.board in ("feather_m0_express", "feather_huzzah"):
from bitbangio import I2C
elif agnostic.board == "pyboard":
from busio import I2C
else:
raise NotImplementedError("Board not supported")

+ 8
- 0
test/src/testing/microcontroller/__init__.py View File

@ -0,0 +1,8 @@
from adafruit_blinka.agnostic import microcontroller
if microcontroller == "esp8266":
pin_count = 10
elif microcontroller == "samd21":
pin_count = 38
else:
raise NotImplementedError("Microcontroller not supported")

+ 0
- 0
test/src/testing/universal/__init__.py View File


+ 85
- 0
test/src/testing/universal/digitalio.py View File

@ -0,0 +1,85 @@
import unittest
from testing import yes_no, await_true
from testing.board import led_pin, default_pin, led_hardwired, led_inverted
from digitalio import *
class TestDigitalInOut(unittest.TestCase):
def test_default(self):
"""DigitalInOut is input with no pull when constructed"""
with DigitalInOut(default_pin) as dio:
self.assertEqual(dio.direction, Direction.INPUT)
self.assertEqual(dio.pull, None)
def test_switch_to_output(self):
"""Default configuration of switch_to_output is respected"""
with DigitalInOut(default_pin) as dio:
dio.switch_to_output()
self.assertEqual(dio.direction, Direction.OUTPUT)
self.assertEqual(dio.value, False)
self.assertEqual(dio.drive_mode, DriveMode.PUSH_PULL)
def test_switch_to_input(self):
"""Default configuration of switch_to_input is respected"""
with DigitalInOut(default_pin) as dio:
dio.switch_to_output() # starts as input anyway
dio.switch_to_input()
self.assertEqual(dio.direction, Direction.INPUT)
self.assertEqual(dio.pull, None)
class TestDigitalInOutInteractive(unittest.TestCase):
def test_blink(self):
"""LED blinks when proper attributes set"""
print()
from adafruit_blinka.agnostic import sleep
if not(led_hardwired) and not(yes_no("Is LED wired to {}".format(led_pin))):
return # test trivially passed
with DigitalInOut(led_pin) as led:
led.direction = Direction.OUTPUT
# should now be OUT, PUSH_PULL, value=0, and LED should light
led.value = False if led_inverted else True
self.assertTrue(yes_no("Is LED lit"))
print("Winking LED...")
for count in range(2):
led.value = not(led.value)
sleep(0.5)
led.value = not(led.value)
sleep(0.5)
self.assertTrue(yes_no("Did LED wink twice"))
def test_button_pull_up(self):
print()
"""Pull-up button configured and detected"""
with DigitalInOut(default_pin) as button:
#button.direction = Direction.INPUT # implied
try:
button.pull = Pull.UP
except NotImplementedError as e:
print(e)
return # pull unsupported, test trivially passed
except Exception as e:
print(e)
return # pull unsupported, test trivially passed
if yes_no("Is Button wired from {} to GND".format(default_pin)):
self.assertTrue(button.value == True)
self.assertTrue(await_true("button pressed", lambda: button.value == False))
def test_button_pull_down(self):
print()
"""Pull-down button configured and detected"""
with DigitalInOut(default_pin) as button:
#button.direction = Direction.INPUT # implied
try:
button.pull = Pull.DOWN
except NotImplementedError as e:
print(e)
return # pull unsupported, test trivially passed
except Exception as e:
print(e)
return # pull unsupported, test trivially passed
if (yes_no("Is Button wired from {} to VCC".format(default_pin))):
self.assertTrue(button.value == False)
self.assertTrue(await_true("button pressed", lambda: button.value == True))

+ 92
- 0
test/src/testing/universal/i2c.py View File

@ -0,0 +1,92 @@
import gc
from testing import yes_no
gc.collect()
from unittest import TestCase
gc.collect()
from testing.board.i2c import I2C
gc.collect()
class TestBME280Interactive(TestCase):
def test_read_value(self):
import board
gc.collect()
import adafruit_bme280
gc.collect()
if not(yes_no("Is BME280 wired to SCL {} SDA {}".format(board.SCL, board.SDA))):
return # test trivially passed
i2c = I2C(board.SCL, board.SDA)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
temperature = bme280.temperature
humidity = bme280.humidity
pressure = bme280.pressure
altitude = bme280.altitude
self.assertTrue(type(temperature) is float )
self.assertTrue(type(humidity) is float )
self.assertTrue(type(pressure) is float )
self.assertTrue(type(altitude) is float )
self.assertTrue( -50 <= temperature <= 50)
self.assertTrue( 0 <= humidity <= 100)
self.assertTrue( 900 <= pressure <= 1100)
self.assertTrue( -1000 <= altitude <= 9,848)
class TestMMA8451Interactive(TestCase):
def test_read_value(self):
import math
gc.collect()
import board
gc.collect()
if not(yes_no("Is MMA8451 wired to SCL {} SDA {} and held still".format(board.SCL, board.SDA))):
return # test trivially passed
# from https://github.com/adafruit/Adafruit_CircuitPython_MMA8451/blob/29e31a0bb836367bc73763b83513105252b7b264/examples/simpletest.py
import adafruit_mma8451
i2c = I2C(board.SCL, board.SDA)
sensor = adafruit_mma8451.MMA8451(i2c)
x, y, z = sensor.acceleration
absolute = math.sqrt(x**2 + y**2 + z**2)
self.assertTrue(9 <=absolute <= 11, "Not earth gravity")
orientation = sensor.orientation
self.assertTrue(orientation in (
adafruit_mma8451.PL_PUF,
adafruit_mma8451.PL_PUB,
adafruit_mma8451.PL_PDF,
adafruit_mma8451.PL_PDB,
adafruit_mma8451.PL_LRF,
adafruit_mma8451.PL_LRB,
adafruit_mma8451.PL_LLF,
adafruit_mma8451.PL_LLB,
))
class TestBNO055Interactive(TestCase):
def test_read_value(self):
"""
Access all sensor values as per
https://github.com/adafruit/Adafruit_CircuitPython_BNO055/blob/bdf6ada21e7552c242bc470d4d2619b480b4c574/examples/values.py
Note I have not successfully run this test. Possibly a hardware issue with module I have.
See https://forums.adafruit.com/viewtopic.php?f=60&t=131665
"""
import board
gc.collect()
import adafruit_bno055
gc.collect()
i2c = I2C(board.SCL, board.SDA)
sensor = adafruit_bno055.BNO055(i2c)
self.assertTrue(9 <= sensor.gravity <= 11)
self.assertTrue(sensor.temperature != 0)
self.assertTrue(sensor.acceleration != (0,0,0))
self.assertTrue(sensor.magnetometer != (0,0,0))
self.assertTrue(sensor.gyroscope != (0,0,0))
self.assertTrue(sensor.quaternion != (0,0,0,0))
sensor.euler
sensor.linear_acceleration

+ 14
- 0
test/src/testing/universal/microcontroller.py View File

@ -0,0 +1,14 @@
import unittest
class TestMicrocontrollerModule(unittest.TestCase):
def test_pins_exist(self):
"""The microcontroller module should contain pin references"""
import microcontroller
from microcontroller import pin
from testing.microcontroller import pin_count
entries = [getattr(pin, key) for key in dir(pin)]
# is this filter line needed? any other types valid in pin module?
entries = list(filter(lambda val: type(val) is microcontroller.Pin, entries))
self.assertTrue(len(entries) > 0)
self.assertTrue(len(entries) == pin_count)

+ 38
- 0
test/src/testing/universal/uart.py View File

@ -0,0 +1,38 @@
import gc
from unittest import TestCase
from testing import await_true
gc.collect()
class TestGPSInteractive(TestCase):
def test_read_value(self):
import adafruit_blinka
adafruit_blinka.patch_system() # needed before adafruit_gps imports time
import microcontroller.pin
gc.collect()
import busio
gc.collect()
import adafruit_gps
gc.collect()
# configure the last available UART (first uart often for REPL)
uartId, uartTx, uartRx = microcontroller.pin.uartPorts[0]
uart = busio.UART(uartTx, uartRx, baudrate=9600, timeout=3000)
gps = adafruit_gps.GPS(uart)
gps.send_command('PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
gps.send_command('PMTK220,1000')
def try_fix():
gps.update()
return gps.has_fix
await_true("GPS fix", try_fix)
self.assertTrue(gps.satellites is not None)
self.assertTrue(-90 <= gps.latitude < 90)
self.assertTrue(-180 <= gps.longitude < 180)

+ 233
- 0
test/src/unittest.py View File

@ -0,0 +1,233 @@
"""Based on https://raw.githubusercontent.com/micropython/micropython-lib/cfa1b9cce0c93a3115bbff3886c9bbcddd9e8047/unittest/unittest.py """
import sys
class SkipTest(Exception):
pass
raiseException = False
raiseBaseException = True
class AssertRaisesContext:
def __init__(self, exc):
self.expected = exc
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, tb):
if exc_type is None:
assert False, "%r not raised" % self.expected
if issubclass(exc_type, self.expected):
return True
return False
class TestCase:
def fail(self, msg=''):
assert False, msg
def assertEqual(self, x, y, msg=''):
if not msg:
msg = "%r vs (expected) %r" % (x, y)
assert x == y, msg
def assertNotEqual(self, x, y, msg=''):
if not msg:
msg = "%r not expected to be equal %r" % (x, y)
assert x != y, msg
def assertAlmostEqual(self, x, y, places=None, msg='', delta=None):
if x == y:
return
if delta is not None and places is not None:
raise TypeError("specify delta or places not both")
if delta is not None:
if abs(x - y) <= delta:
return
if not msg:
msg = '%r != %r within %r delta' % (x, y, delta)
else:
if places is None:
places = 7
if round(abs(y-x), places) == 0:
return
if not msg:
msg = '%r != %r within %r places' % (x, y, places)
assert False, msg
def assertNotAlmostEqual(self, x, y, places=None, msg='', delta=None):
if delta is not None and places is not None:
raise TypeError("specify delta or places not both")
if delta is not None:
if not (x == y) and abs(x - y) > delta:
return
if not msg: