+*.mpy
+.idea
__pycache__
_build
*.pyc
--- /dev/null
+[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
: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
============
--- /dev/null
+# 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.
\ No newline at end of file
--- /dev/null
+"""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
\ No newline at end of file
--- /dev/null
+"""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()
--- /dev/null
+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
\ No newline at end of file
--- /dev/null
+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
\ No newline at end of file
--- /dev/null
+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
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+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 = ()
\ No newline at end of file
--- /dev/null
+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),
+)
+
--- /dev/null
+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)
# 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()
--- /dev/null
+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)
--- /dev/null
+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)
--- /dev/null
+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")
\ No newline at end of file
--- /dev/null
+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")
\ No newline at end of file
--- /dev/null
+Subproject commit 3219f5ccd5451f1e11a519d9d0d5407237f84d45
--- /dev/null
+Subproject commit 978c4c55270c5538dfa84117f426b7ace66ef017
--- /dev/null
+Subproject commit eb7720b0d8dff377e687157e3f052f18a478e4a5
--- /dev/null
+Subproject commit cd71268274f6a025ff2d944e0e1781b7435dd426
--- /dev/null
+Subproject commit f389f1f57f5567a8e23901346f264285f432a061
--- /dev/null
+Subproject commit f86b4549c1f8ec10682cb5e5148693dc29c85602
--- /dev/null
+Subproject commit 1abb4f7ce6fa5513c4e9c7dc280c1c2c28a7d062
--- /dev/null
+#!/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
--- /dev/null
+#!/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 {} {}"
\ No newline at end of file
--- /dev/null
+#!/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}"
--- /dev/null
+# 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()
\ No newline at end of file
--- /dev/null
+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)
--- /dev/null
+"""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")
\ No newline at end of file
--- /dev/null
+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")
\ No newline at end of file
--- /dev/null
+from adafruit_blinka.agnostic import microcontroller
+
+if microcontroller == "esp8266":
+ pin_count = 10
+elif microcontroller == "samd21":
+ pin_count = 38
+else:
+ raise NotImplementedError("Microcontroller not supported")
--- /dev/null
+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))
+
--- /dev/null
+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
--- /dev/null
+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)
\ No newline at end of file
--- /dev/null
+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)
+
--- /dev/null
+"""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:
+ msg = '%r == %r within %r delta' % (x, y, delta)
+ else:
+ if places is None:
+ places = 7
+ if not (x == y) and round(abs(y-x), places) != 0:
+ return
+ if not msg:
+ msg = '%r == %r within %r places' % (x, y, places)
+
+ assert False, msg
+
+ def assertIs(self, x, y, msg=''):
+ if not msg:
+ msg = "%r is not %r" % (x, y)
+ assert x is y, msg
+
+ def assertIsNot(self, x, y, msg=''):
+ if not msg:
+ msg = "%r is %r" % (x, y)
+ assert x is not y, msg
+
+ def assertIsNone(self, x, msg=''):
+ if not msg:
+ msg = "%r is not None" % x
+ assert x is None, msg
+
+ def assertIsNotNone(self, x, msg=''):
+ if not msg:
+ msg = "%r is None" % x
+ assert x is not None, msg
+
+ def assertTrue(self, x, msg=''):
+ if not msg:
+ msg = "Expected %r to be True" % x
+ assert x, msg
+
+ def assertFalse(self, x, msg=''):
+ if not msg:
+ msg = "Expected %r to be False" % x
+ assert not x, msg
+
+ def assertIn(self, x, y, msg=''):
+ if not msg:
+ msg = "Expected %r to be in %r" % (x, y)
+ assert x in y, msg
+
+ def assertIsInstance(self, x, y, msg=''):
+ assert isinstance(x, y), msg
+
+ def assertRaises(self, exc, func=None, *args, **kwargs):
+ if func is None:
+ return AssertRaisesContext(exc)
+
+ try:
+ func(*args, **kwargs)
+ assert False, "%r not raised" % exc
+ except Exception as e:
+ if isinstance(e, exc):
+ return
+ raise
+
+
+
+def skip(msg):
+ def _decor(fun):
+ # We just replace original fun with _inner
+ def _inner(self):
+ raise SkipTest(msg)
+ return _inner
+ return _decor
+
+def skipIf(cond, msg):
+ if not cond:
+ return lambda x: x
+ return skip(msg)
+
+def skipUnless(cond, msg):
+ if cond:
+ return lambda x: x
+ return skip(msg)
+
+
+class TestSuite:
+ def __init__(self):
+ self.tests = []
+ def addTest(self, cls):
+ self.tests.append(cls)
+
+class TestRunner:
+ def run(self, suite):
+ res = TestResult()
+ for c in suite.tests:
+ run_class(c, res)
+
+ print("Ran %d tests\n" % res.testsRun)
+ if res.failuresNum > 0 or res.errorsNum > 0:
+ print("FAILED (failures=%d, errors=%d)" % (res.failuresNum, res.errorsNum))
+ else:
+ msg = "OK"
+ if res.skippedNum > 0:
+ msg += " (%d skipped)" % res.skippedNum
+ print(msg)
+
+ return res
+
+class TestResult:
+ def __init__(self):
+ self.errorsNum = 0
+ self.failuresNum = 0
+ self.skippedNum = 0
+ self.testsRun = 0
+
+ def wasSuccessful(self):
+ return self.errorsNum == 0 and self.failuresNum == 0
+
+# TODO: Uncompliant
+def run_class(c, test_result):
+ o = c()
+ set_up = getattr(o, "setUp", lambda: None)
+ tear_down = getattr(o, "tearDown", lambda: None)
+ for name in dir(o):
+ if name.startswith("test"):
+ print("%s (%s) ..." % (name, c.__qualname__), end="")
+ m = getattr(o, name)
+ set_up()
+ try:
+ test_result.testsRun += 1
+ m()
+ print(" ok")
+ except SkipTest as e:
+ print(" skipped:", e.args[0])
+ test_result.skippedNum += 1
+ except Exception as e: # user exception
+ print(" FAIL")
+ if raiseException:
+ raise
+ else:
+ print(e)
+ test_result.failuresNum += 1
+ continue
+ except BaseException as e: # system exception
+ print(" FAIL")
+ if raiseBaseException:
+ raise
+ else:
+ print(e)
+ test_result.failuresNum += 1
+ continue
+ finally:
+ tear_down()
+
+
+def main(module="__main__"):
+ def test_cases(m):
+ for tn in dir(m):
+ c = getattr(m, tn)
+ if isinstance(c, object) and isinstance(c, type) and issubclass(c, TestCase):
+ yield c
+
+ m = __import__(module) # changed to permit non-top-level testing modules
+ suite = TestSuite()
+ for c in test_cases(m):
+ suite.addTest(c)
+ runner = TestRunner()
+ result = runner.run(suite)
\ No newline at end of file