Updated UM boards
This commit is contained in:
parent
2bb44f6c4d
commit
a2a0aa058f
198
ports/esp32s2/boards/unexpectedmaker_feathers2/adafruit_dotstar.py
Executable file
198
ports/esp32s2/boards/unexpectedmaker_feathers2/adafruit_dotstar.py
Executable file
@ -0,0 +1,198 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2016 Damien P. George (original Neopixel object)
|
||||
# Copyright (c) 2017 Ladyada
|
||||
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
# Copyright (c) 2019 Roy Hooper
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
`adafruit_dotstar` - DotStar strip driver (for CircuitPython 5.0+ with _pixelbuf)
|
||||
=================================================================================
|
||||
|
||||
* Author(s): Damien P. George, Limor Fried, Scott Shawcroft & Roy Hooper
|
||||
"""
|
||||
|
||||
# pylint: disable=ungrouped-imports
|
||||
import sys
|
||||
import busio
|
||||
import digitalio
|
||||
|
||||
if sys.implementation.version[0] < 5:
|
||||
import adafruit_pypixelbuf as _pixelbuf
|
||||
else:
|
||||
try:
|
||||
import _pixelbuf
|
||||
except ImportError:
|
||||
import adafruit_pypixelbuf as _pixelbuf
|
||||
|
||||
__version__ = "0.0.0-auto.0"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git"
|
||||
|
||||
START_HEADER_SIZE = 4
|
||||
|
||||
# Pixel color order constants
|
||||
RBG = "PRBG"
|
||||
"""Red Blue Green"""
|
||||
RGB = "PRGB"
|
||||
"""Red Green Blue"""
|
||||
GRB = "PGRB"
|
||||
"""Green Red Blue"""
|
||||
GBR = "PGBR"
|
||||
"""Green Blue Red"""
|
||||
BRG = "PBRG"
|
||||
"""Blue Red Green"""
|
||||
BGR = "PBGR"
|
||||
"""Blue Green Red"""
|
||||
|
||||
|
||||
class DotStar(_pixelbuf.PixelBuf):
|
||||
"""
|
||||
A sequence of dotstars.
|
||||
|
||||
:param ~microcontroller.Pin clock: The pin to output dotstar clock on.
|
||||
:param ~microcontroller.Pin data: The pin to output dotstar data on.
|
||||
:param int n: The number of dotstars in the chain
|
||||
:param float brightness: Brightness of the pixels between 0.0 and 1.0
|
||||
:param bool auto_write: True if the dotstars should immediately change when
|
||||
set. If False, `show` must be called explicitly.
|
||||
:param str pixel_order: Set the pixel order on the strip - different
|
||||
strips implement this differently. If you send red, and it looks blue
|
||||
or green on the strip, modify this! It should be one of the values above.
|
||||
:param int baudrate: Desired clock rate if using hardware SPI (ignored if
|
||||
using 'soft' SPI). This is only a recommendation; the actual clock
|
||||
rate may be slightly different depending on what the system hardware
|
||||
can provide.
|
||||
|
||||
Example for Gemma M0:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import adafruit_dotstar
|
||||
import time
|
||||
from board import *
|
||||
|
||||
RED = 0x100000
|
||||
|
||||
with adafruit_dotstar.DotStar(APA102_SCK, APA102_MOSI, 1) as pixels:
|
||||
pixels[0] = RED
|
||||
time.sleep(2)
|
||||
|
||||
.. py:method:: DotStar.show()
|
||||
|
||||
Shows the new colors on the dotstars themselves if they haven't already
|
||||
been autowritten.
|
||||
|
||||
The colors may or may not be showing after this function returns because
|
||||
it may be done asynchronously.
|
||||
|
||||
.. py:method:: DotStar.fill(color)
|
||||
|
||||
Colors all dotstars the given ***color***.
|
||||
|
||||
.. py:attribute:: brightness
|
||||
|
||||
Overall brightness of all dotstars (0 to 1.0)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
clock,
|
||||
data,
|
||||
n,
|
||||
*,
|
||||
brightness=1.0,
|
||||
auto_write=True,
|
||||
pixel_order=BGR,
|
||||
baudrate=4000000
|
||||
):
|
||||
self._spi = None
|
||||
try:
|
||||
self._spi = busio.SPI(clock, MOSI=data)
|
||||
while not self._spi.try_lock():
|
||||
pass
|
||||
self._spi.configure(baudrate=baudrate)
|
||||
|
||||
except (NotImplementedError, ValueError):
|
||||
self.dpin = digitalio.DigitalInOut(data)
|
||||
self.cpin = digitalio.DigitalInOut(clock)
|
||||
self.dpin.direction = digitalio.Direction.OUTPUT
|
||||
self.cpin.direction = digitalio.Direction.OUTPUT
|
||||
self.cpin.value = False
|
||||
|
||||
# Supply one extra clock cycle for each two pixels in the strip.
|
||||
trailer_size = n // 16
|
||||
if n % 16 != 0:
|
||||
trailer_size += 1
|
||||
|
||||
# Four empty bytes for the header.
|
||||
header = bytearray(START_HEADER_SIZE)
|
||||
# 0xff bytes for the trailer.
|
||||
trailer = bytearray(b"\xff") * trailer_size
|
||||
|
||||
super().__init__(
|
||||
n,
|
||||
byteorder=pixel_order,
|
||||
brightness=brightness,
|
||||
auto_write=auto_write,
|
||||
header=header,
|
||||
trailer=trailer,
|
||||
)
|
||||
|
||||
def deinit(self):
|
||||
"""Blank out the DotStars and release the resources."""
|
||||
self.fill(0)
|
||||
self.show()
|
||||
if self._spi:
|
||||
self._spi.deinit()
|
||||
else:
|
||||
self.dpin.deinit()
|
||||
self.cpin.deinit()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
self.deinit()
|
||||
|
||||
def __repr__(self):
|
||||
return "[" + ", ".join([str(x) for x in self]) + "]"
|
||||
|
||||
@property
|
||||
def n(self):
|
||||
"""
|
||||
The number of dotstars in the chain (read-only)
|
||||
"""
|
||||
return len(self)
|
||||
|
||||
def _transmit(self, buffer):
|
||||
if self._spi:
|
||||
self._spi.write(buffer)
|
||||
else:
|
||||
self._ds_writebytes(buffer)
|
||||
|
||||
def _ds_writebytes(self, buffer):
|
||||
for b in buffer:
|
||||
for _ in range(8):
|
||||
self.dpin.value = b & 0x80
|
||||
self.cpin.value = True
|
||||
self.cpin.value = False
|
||||
b = b << 1
|
||||
self.cpin.value = False
|
374
ports/esp32s2/boards/unexpectedmaker_feathers2/adafruit_pypixelbuf.py
Executable file
374
ports/esp32s2/boards/unexpectedmaker_feathers2/adafruit_pypixelbuf.py
Executable file
@ -0,0 +1,374 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Based on the Adafruit NeoPixel and Adafruit Dotstar CircuitPython drivers.
|
||||
# Copyright (c) 2019-2020 Roy Hooper
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
`adafruit_pypixelbuf` - A pure python implementation of _pixelbuf
|
||||
=================================================================
|
||||
This class is used when _pixelbuf is not available in CircuitPython. It is based on the work
|
||||
in neopixel.py and adafruit_dotstar.py.
|
||||
|
||||
* Author(s): Damien P. George & Limor Fried & Scott Shawcroft & Roy Hooper
|
||||
"""
|
||||
|
||||
DOTSTAR_LED_START_FULL_BRIGHT = 0xFF
|
||||
DOTSTAR_LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits
|
||||
DOTSTAR_LED_BRIGHTNESS = 0b00011111
|
||||
|
||||
|
||||
class PixelBuf: # pylint: disable=too-many-instance-attributes
|
||||
"""
|
||||
A sequence of RGB/RGBW pixels.
|
||||
|
||||
This is the pure python implementation of CircuitPython's _pixelbuf.
|
||||
|
||||
:param ~int n: Number of pixels
|
||||
:param ~str byteorder: Byte order string constant (also sets bpp)
|
||||
:param ~float brightness: Brightness (0 to 1.0, default 1.0)
|
||||
:param ~bool auto_write: Whether to automatically write pixels (Default False)
|
||||
:param bytes header: Sequence of bytes to always send before pixel values.
|
||||
:param bytes trailer: Sequence of bytes to always send after pixel values.
|
||||
"""
|
||||
|
||||
def __init__( # pylint: disable=too-many-locals,too-many-arguments
|
||||
self,
|
||||
n,
|
||||
byteorder="BGR",
|
||||
brightness=1.0,
|
||||
auto_write=False,
|
||||
header=None,
|
||||
trailer=None,
|
||||
):
|
||||
|
||||
bpp, byteorder_tuple, has_white, dotstar_mode = self.parse_byteorder(byteorder)
|
||||
|
||||
self.auto_write = False
|
||||
|
||||
effective_bpp = 4 if dotstar_mode else bpp
|
||||
_bytes = effective_bpp * n
|
||||
buf = bytearray(_bytes)
|
||||
offset = 0
|
||||
|
||||
if header is not None:
|
||||
if not isinstance(header, bytearray):
|
||||
raise TypeError("header must be a bytearray")
|
||||
buf = header + buf
|
||||
offset = len(header)
|
||||
|
||||
if trailer is not None:
|
||||
if not isinstance(trailer, bytearray):
|
||||
raise TypeError("trailer must be a bytearray")
|
||||
buf += trailer
|
||||
|
||||
self._pixels = n
|
||||
self._bytes = _bytes
|
||||
self._byteorder = byteorder_tuple
|
||||
self._byteorder_string = byteorder
|
||||
self._has_white = has_white
|
||||
self._bpp = bpp
|
||||
self._pre_brightness_buffer = None
|
||||
self._post_brightness_buffer = buf
|
||||
self._offset = offset
|
||||
self._dotstar_mode = dotstar_mode
|
||||
self._pixel_step = effective_bpp
|
||||
|
||||
if dotstar_mode:
|
||||
self._byteorder_tuple = (
|
||||
byteorder_tuple[0] + 1,
|
||||
byteorder_tuple[1] + 1,
|
||||
byteorder_tuple[2] + 1,
|
||||
0,
|
||||
)
|
||||
# Initialize the buffer with the dotstar start bytes.
|
||||
for i in range(self._offset, self._bytes + self._offset, 4):
|
||||
self._post_brightness_buffer[i] = DOTSTAR_LED_START_FULL_BRIGHT
|
||||
|
||||
self._brightness = 1.0
|
||||
self.brightness = brightness
|
||||
|
||||
self.auto_write = auto_write
|
||||
|
||||
@staticmethod
|
||||
def parse_byteorder(byteorder):
|
||||
"""
|
||||
Parse a Byteorder string for validity and determine bpp, byte order, and
|
||||
dostar brightness bits.
|
||||
|
||||
Byteorder strings may contain the following characters:
|
||||
R - Red
|
||||
G - Green
|
||||
B - Blue
|
||||
W - White
|
||||
P - PWM (PWM Duty cycle for pixel - dotstars 0 - 1.0)
|
||||
|
||||
:param: ~str bpp: bpp string.
|
||||
:return: ~tuple: bpp, byteorder, has_white, dotstar_mode
|
||||
"""
|
||||
bpp = len(byteorder)
|
||||
dotstar_mode = False
|
||||
has_white = False
|
||||
|
||||
if byteorder.strip("RGBWP") != "":
|
||||
raise ValueError("Invalid Byteorder string")
|
||||
|
||||
try:
|
||||
r = byteorder.index("R")
|
||||
g = byteorder.index("G")
|
||||
b = byteorder.index("B")
|
||||
except ValueError:
|
||||
raise ValueError("Invalid Byteorder string")
|
||||
if "W" in byteorder:
|
||||
w = byteorder.index("W")
|
||||
byteorder = (r, g, b, w)
|
||||
has_white = True
|
||||
elif "P" in byteorder:
|
||||
lum = byteorder.index("P")
|
||||
byteorder = (r, g, b, lum)
|
||||
dotstar_mode = True
|
||||
else:
|
||||
byteorder = (r, g, b)
|
||||
|
||||
return bpp, byteorder, has_white, dotstar_mode
|
||||
|
||||
@property
|
||||
def bpp(self):
|
||||
"""
|
||||
The number of bytes per pixel in the buffer (read-only).
|
||||
"""
|
||||
return self._bpp
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""
|
||||
Float value between 0 and 1. Output brightness.
|
||||
|
||||
When brightness is less than 1.0, a second buffer will be used to store the color values
|
||||
before they are adjusted for brightness.
|
||||
"""
|
||||
return self._brightness
|
||||
|
||||
@brightness.setter
|
||||
def brightness(self, value):
|
||||
value = min(max(value, 0.0), 1.0)
|
||||
change = value - self._brightness
|
||||
if -0.001 < change < 0.001:
|
||||
return
|
||||
|
||||
self._brightness = value
|
||||
|
||||
if self._pre_brightness_buffer is None:
|
||||
self._pre_brightness_buffer = bytearray(self._post_brightness_buffer)
|
||||
|
||||
# Adjust brightness of existing pixels
|
||||
offset_check = self._offset % self._pixel_step
|
||||
for i in range(self._offset, self._bytes + self._offset):
|
||||
# Don't adjust per-pixel luminance bytes in dotstar mode
|
||||
if self._dotstar_mode and (i % 4 != offset_check):
|
||||
continue
|
||||
self._post_brightness_buffer[i] = int(
|
||||
self._pre_brightness_buffer[i] * self._brightness
|
||||
)
|
||||
|
||||
if self.auto_write:
|
||||
self.show()
|
||||
|
||||
@property
|
||||
def byteorder(self):
|
||||
"""
|
||||
ByteOrder string for the buffer (read-only)
|
||||
"""
|
||||
return self._byteorder_string
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Number of pixels.
|
||||
"""
|
||||
return self._pixels
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
Call the associated write function to display the pixels
|
||||
"""
|
||||
return self._transmit(self._post_brightness_buffer)
|
||||
|
||||
def fill(self, color):
|
||||
"""
|
||||
Fills the given pixelbuf with the given color.
|
||||
:param pixelbuf: A pixel object.
|
||||
:param color: Color to set.
|
||||
"""
|
||||
r, g, b, w = self._parse_color(color)
|
||||
for i in range(self._pixels):
|
||||
self._set_item(i, r, g, b, w)
|
||||
if self.auto_write:
|
||||
self.show()
|
||||
|
||||
def _parse_color(self, value):
|
||||
r = 0
|
||||
g = 0
|
||||
b = 0
|
||||
w = 0
|
||||
if isinstance(value, int):
|
||||
r = value >> 16
|
||||
g = (value >> 8) & 0xFF
|
||||
b = value & 0xFF
|
||||
w = 0
|
||||
|
||||
if self._dotstar_mode:
|
||||
w = 1.0
|
||||
else:
|
||||
if len(value) < 3 or len(value) > 4:
|
||||
raise ValueError(
|
||||
"Expected tuple of length {}, got {}".format(self._bpp, len(value))
|
||||
)
|
||||
if len(value) == self._bpp:
|
||||
if self._bpp == 3:
|
||||
r, g, b = value
|
||||
else:
|
||||
r, g, b, w = value
|
||||
elif len(value) == 3:
|
||||
r, g, b = value
|
||||
if self._dotstar_mode:
|
||||
w = 1.0
|
||||
|
||||
if self._bpp == 4:
|
||||
if self._dotstar_mode:
|
||||
# LED startframe is three "1" bits, followed by 5 brightness bits
|
||||
# then 8 bits for each of R, G, and B. The order of those 3 are configurable and
|
||||
# vary based on hardware
|
||||
w = (int(w * 31) & 0b00011111) | DOTSTAR_LED_START
|
||||
elif (
|
||||
self._has_white
|
||||
and (isinstance(value, int) or len(value) == 3)
|
||||
and r == g
|
||||
and g == b
|
||||
):
|
||||
# If all components are the same and we have a white pixel then use it
|
||||
# instead of the individual components when all 4 values aren't explicitly given.
|
||||
w = r
|
||||
r = 0
|
||||
g = 0
|
||||
b = 0
|
||||
|
||||
return (r, g, b, w)
|
||||
|
||||
def _set_item(
|
||||
self, index, r, g, b, w
|
||||
): # pylint: disable=too-many-locals,too-many-branches,too-many-arguments
|
||||
if index < 0:
|
||||
index += len(self)
|
||||
if index >= self._pixels or index < 0:
|
||||
raise IndexError
|
||||
offset = self._offset + (index * self._bpp)
|
||||
|
||||
if self._pre_brightness_buffer is not None:
|
||||
if self._bpp == 4:
|
||||
self._pre_brightness_buffer[offset + self._byteorder[3]] = w
|
||||
self._pre_brightness_buffer[offset + self._byteorder[0]] = r
|
||||
self._pre_brightness_buffer[offset + self._byteorder[1]] = g
|
||||
self._pre_brightness_buffer[offset + self._byteorder[2]] = b
|
||||
|
||||
if self._bpp == 4:
|
||||
# Only apply brightness if w is actually white (aka not DotStar.)
|
||||
if not self._dotstar_mode:
|
||||
w = int(w * self._brightness)
|
||||
self._post_brightness_buffer[offset + self._byteorder[3]] = w
|
||||
|
||||
self._post_brightness_buffer[offset + self._byteorder[0]] = int(
|
||||
r * self._brightness
|
||||
)
|
||||
self._post_brightness_buffer[offset + self._byteorder[1]] = int(
|
||||
g * self._brightness
|
||||
)
|
||||
self._post_brightness_buffer[offset + self._byteorder[2]] = int(
|
||||
b * self._brightness
|
||||
)
|
||||
|
||||
def __setitem__(self, index, val):
|
||||
if isinstance(index, slice):
|
||||
start, stop, step = index.indices(self._pixels)
|
||||
for val_i, in_i in enumerate(range(start, stop, step)):
|
||||
r, g, b, w = self._parse_color(val[val_i])
|
||||
self._set_item(in_i, r, g, b, w)
|
||||
else:
|
||||
r, g, b, w = self._parse_color(val)
|
||||
self._set_item(index, r, g, b, w)
|
||||
|
||||
if self.auto_write:
|
||||
self.show()
|
||||
|
||||
def _getitem(self, index):
|
||||
start = self._offset + (index * self._bpp)
|
||||
buffer = (
|
||||
self._pre_brightness_buffer
|
||||
if self._pre_brightness_buffer is not None
|
||||
else self._post_brightness_buffer
|
||||
)
|
||||
value = [
|
||||
buffer[start + self._byteorder[0]],
|
||||
buffer[start + self._byteorder[1]],
|
||||
buffer[start + self._byteorder[2]],
|
||||
]
|
||||
if self._has_white:
|
||||
value.append(buffer[start + self._byteorder[3]])
|
||||
elif self._dotstar_mode:
|
||||
value.append(
|
||||
(buffer[start + self._byteorder[3]] & DOTSTAR_LED_BRIGHTNESS) / 31.0
|
||||
)
|
||||
return value
|
||||
|
||||
def __getitem__(self, index):
|
||||
if isinstance(index, slice):
|
||||
out = []
|
||||
for in_i in range(
|
||||
*index.indices(len(self._post_brightness_buffer) // self._bpp)
|
||||
):
|
||||
out.append(self._getitem(in_i))
|
||||
return out
|
||||
if index < 0:
|
||||
index += len(self)
|
||||
if index >= self._pixels or index < 0:
|
||||
raise IndexError
|
||||
return self._getitem(index)
|
||||
|
||||
def _transmit(self, buffer):
|
||||
raise NotImplementedError("Must be subclassed")
|
||||
|
||||
|
||||
def wheel(pos):
|
||||
"""
|
||||
Helper to create a colorwheel.
|
||||
|
||||
:param pos: int 0-255 of color value to return
|
||||
:return: tuple of RGB values
|
||||
"""
|
||||
# Input a value 0 to 255 to get a color value.
|
||||
# The colours are a transition r - g - b - back to r.
|
||||
if pos < 0 or pos > 255:
|
||||
return 0, 0, 0
|
||||
if pos < 85:
|
||||
return 255 - pos * 3, pos * 3, 0
|
||||
if pos < 170:
|
||||
pos -= 85
|
||||
return 0, 255 - pos * 3, pos * 3
|
||||
pos -= 170
|
||||
return pos * 3, 0, 255 - pos * 3
|
311
ports/esp32s2/boards/unexpectedmaker_feathers2/adafruit_requests.py
Executable file
311
ports/esp32s2/boards/unexpectedmaker_feathers2/adafruit_requests.py
Executable file
@ -0,0 +1,311 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2019 ladyada for Adafruit Industries
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
"""
|
||||
`adafruit_requests`
|
||||
================================================================================
|
||||
|
||||
A requests-like library for web interfacing
|
||||
|
||||
|
||||
* Author(s): ladyada, Paul Sokolovsky
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
Adapted from https://github.com/micropython/micropython-lib/tree/master/urequests
|
||||
|
||||
micropython-lib consists of multiple modules from different sources and
|
||||
authors. Each module comes under its own licensing terms. Short name of
|
||||
a license can be found in a file within a module directory (usually
|
||||
metadata.txt or setup.py). Complete text of each license used is provided
|
||||
at https://github.com/micropython/micropython-lib/blob/master/LICENSE
|
||||
|
||||
author='Paul Sokolovsky'
|
||||
license='MIT'
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* Adafruit CircuitPython firmware for the supported boards:
|
||||
https://github.com/adafruit/circuitpython/releases
|
||||
|
||||
"""
|
||||
|
||||
import gc
|
||||
|
||||
__version__ = "0.0.0-auto.0"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Requests.git"
|
||||
|
||||
_the_interface = None # pylint: disable=invalid-name
|
||||
_the_sock = None # pylint: disable=invalid-name
|
||||
|
||||
|
||||
def set_socket(sock, iface=None):
|
||||
"""Helper to set the global socket and optionally set the global network interface.
|
||||
:param sock: socket object.
|
||||
:param iface: internet interface object
|
||||
|
||||
"""
|
||||
global _the_sock # pylint: disable=invalid-name, global-statement
|
||||
_the_sock = sock
|
||||
if iface:
|
||||
global _the_interface # pylint: disable=invalid-name, global-statement
|
||||
_the_interface = iface
|
||||
_the_sock.set_interface(iface)
|
||||
|
||||
|
||||
class Response:
|
||||
"""The response from a request, contains all the headers/content"""
|
||||
|
||||
encoding = None
|
||||
|
||||
def __init__(self, sock):
|
||||
self.socket = sock
|
||||
self.encoding = "utf-8"
|
||||
self._cached = None
|
||||
self.status_code = None
|
||||
self.reason = None
|
||||
self._read_so_far = 0
|
||||
self.headers = {}
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
"""Close, delete and collect the response data"""
|
||||
if self.socket:
|
||||
self.socket.close()
|
||||
del self.socket
|
||||
del self._cached
|
||||
gc.collect()
|
||||
|
||||
@property
|
||||
def content(self):
|
||||
"""The HTTP content direct from the socket, as bytes"""
|
||||
# print(self.headers)
|
||||
try:
|
||||
content_length = int(self.headers["content-length"])
|
||||
except KeyError:
|
||||
content_length = 0
|
||||
# print("Content length:", content_length)
|
||||
if self._cached is None:
|
||||
try:
|
||||
self._cached = self.socket.recv(content_length)
|
||||
finally:
|
||||
self.socket.close()
|
||||
self.socket = None
|
||||
# print("Buffer length:", len(self._cached))
|
||||
return self._cached
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
"""The HTTP content, encoded into a string according to the HTTP
|
||||
header encoding"""
|
||||
return str(self.content, self.encoding)
|
||||
|
||||
def json(self):
|
||||
"""The HTTP content, parsed into a json dictionary"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
try:
|
||||
import json as json_module
|
||||
except ImportError:
|
||||
import ujson as json_module
|
||||
return json_module.loads(self.content)
|
||||
|
||||
def iter_content(self, chunk_size=1, decode_unicode=False):
|
||||
"""An iterator that will stream data by only reading 'chunk_size'
|
||||
bytes and yielding them, when we can't buffer the whole datastream"""
|
||||
if decode_unicode:
|
||||
raise NotImplementedError("Unicode not supported")
|
||||
|
||||
while True:
|
||||
chunk = self.socket.recv(chunk_size)
|
||||
if chunk:
|
||||
yield chunk
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
# pylint: disable=too-many-branches, too-many-statements, unused-argument, too-many-arguments, too-many-locals
|
||||
def request(method, url, data=None, json=None, headers=None, stream=False, timeout=1):
|
||||
"""Perform an HTTP request to the given url which we will parse to determine
|
||||
whether to use SSL ('https://') or not. We can also send some provided 'data'
|
||||
or a json dictionary which we will stringify. 'headers' is optional HTTP headers
|
||||
sent along. 'stream' will determine if we buffer everything, or whether to only
|
||||
read only when requested
|
||||
"""
|
||||
global _the_interface # pylint: disable=global-statement, invalid-name
|
||||
global _the_sock # pylint: disable=global-statement, invalid-name
|
||||
|
||||
if not headers:
|
||||
headers = {}
|
||||
|
||||
try:
|
||||
proto, dummy, host, path = url.split("/", 3)
|
||||
# replace spaces in path
|
||||
path = path.replace(" ", "%20")
|
||||
except ValueError:
|
||||
proto, dummy, host = url.split("/", 2)
|
||||
path = ""
|
||||
if proto == "http:":
|
||||
port = 80
|
||||
elif proto == "https:":
|
||||
port = 443
|
||||
else:
|
||||
raise ValueError("Unsupported protocol: " + proto)
|
||||
|
||||
if ":" in host:
|
||||
host, port = host.split(":", 1)
|
||||
port = int(port)
|
||||
|
||||
addr_info = _the_sock.getaddrinfo(host, port, 0, _the_sock.SOCK_STREAM)[0]
|
||||
sock = _the_sock.socket(addr_info[0], addr_info[1], addr_info[2])
|
||||
resp = Response(sock) # our response
|
||||
|
||||
sock.settimeout(timeout) # socket read timeout
|
||||
|
||||
try:
|
||||
if proto == "https:":
|
||||
conntype = _the_interface.TLS_MODE
|
||||
sock.connect(
|
||||
(host, port), conntype
|
||||
) # for SSL we need to know the host name
|
||||
else:
|
||||
conntype = _the_interface.TCP_MODE
|
||||
sock.connect(addr_info[-1], conntype)
|
||||
sock.send(
|
||||
b"%s /%s HTTP/1.0\r\n" % (bytes(method, "utf-8"), bytes(path, "utf-8"))
|
||||
)
|
||||
if "Host" not in headers:
|
||||
sock.send(b"Host: %s\r\n" % bytes(host, "utf-8"))
|
||||
if "User-Agent" not in headers:
|
||||
sock.send(b"User-Agent: Adafruit CircuitPython\r\n")
|
||||
# Iterate over keys to avoid tuple alloc
|
||||
for k in headers:
|
||||
sock.send(k.encode())
|
||||
sock.send(b": ")
|
||||
sock.send(headers[k].encode())
|
||||
sock.send(b"\r\n")
|
||||
if json is not None:
|
||||
assert data is None
|
||||
# pylint: disable=import-outside-toplevel
|
||||
try:
|
||||
import json as json_module
|
||||
except ImportError:
|
||||
import ujson as json_module
|
||||
# pylint: enable=import-outside-toplevel
|
||||
data = json_module.dumps(json)
|
||||
sock.send(b"Content-Type: application/json\r\n")
|
||||
if data:
|
||||
if isinstance(data, dict):
|
||||
sock.send(b"Content-Type: application/x-www-form-urlencoded\r\n")
|
||||
_post_data = ""
|
||||
for k in data:
|
||||
_post_data = "{}&{}={}".format(_post_data, k, data[k])
|
||||
data = _post_data[1:]
|
||||
sock.send(b"Content-Length: %d\r\n" % len(data))
|
||||
sock.send(b"\r\n")
|
||||
if data:
|
||||
if isinstance(data, bytearray):
|
||||
sock.send(bytes(data))
|
||||
else:
|
||||
sock.send(bytes(data, "utf-8"))
|
||||
|
||||
line = sock.readline()
|
||||
# print(line)
|
||||
line = line.split(None, 2)
|
||||
status = int(line[1])
|
||||
reason = ""
|
||||
if len(line) > 2:
|
||||
reason = line[2].rstrip()
|
||||
resp.headers = parse_headers(sock)
|
||||
if resp.headers.get("transfer-encoding"):
|
||||
if "chunked" in resp.headers.get("transfer-encoding"):
|
||||
raise ValueError("Unsupported " + resp.headers.get("transfer-encoding"))
|
||||
elif resp.headers.get("location") and not 200 <= status <= 299:
|
||||
raise NotImplementedError("Redirects not yet supported")
|
||||
|
||||
except:
|
||||
sock.close()
|
||||
raise
|
||||
|
||||
resp.status_code = status
|
||||
resp.reason = reason
|
||||
return resp
|
||||
|
||||
|
||||
def parse_headers(sock):
|
||||
"""
|
||||
Parses the header portion of an HTTP request/response from the socket.
|
||||
Expects first line of HTTP request/response to have been read already
|
||||
return: header dictionary
|
||||
rtype: Dict
|
||||
"""
|
||||
headers = {}
|
||||
while True:
|
||||
line = sock.readline()
|
||||
if not line or line == b"\r\n":
|
||||
break
|
||||
|
||||
# print("**line: ", line)
|
||||
splits = line.split(b": ", 1)
|
||||
title = splits[0]
|
||||
content = ""
|
||||
if len(splits) > 1:
|
||||
content = splits[1]
|
||||
if title and content:
|
||||
title = str(title.lower(), "utf-8")
|
||||
content = str(content, "utf-8")
|
||||
headers[title] = content
|
||||
return headers
|
||||
|
||||
|
||||
def head(url, **kw):
|
||||
"""Send HTTP HEAD request"""
|
||||
return request("HEAD", url, **kw)
|
||||
|
||||
|
||||
def get(url, **kw):
|
||||
"""Send HTTP GET request"""
|
||||
return request("GET", url, **kw)
|
||||
|
||||
|
||||
def post(url, **kw):
|
||||
"""Send HTTP POST request"""
|
||||
return request("POST", url, **kw)
|
||||
|
||||
|
||||
def put(url, **kw):
|
||||
"""Send HTTP PUT request"""
|
||||
return request("PUT", url, **kw)
|
||||
|
||||
|
||||
def patch(url, **kw):
|
||||
"""Send HTTP PATCH request"""
|
||||
return request("PATCH", url, **kw)
|
||||
|
||||
|
||||
def delete(url, **kw):
|
||||
"""Send HTTP DELETE request"""
|
||||
return request("DELETE", url, **kw)
|
47
ports/esp32s2/boards/unexpectedmaker_feathers2/feathers2.py
Normal file
47
ports/esp32s2/boards/unexpectedmaker_feathers2/feathers2.py
Normal file
@ -0,0 +1,47 @@
|
||||
# FeatherS2 Helper Library
|
||||
# 2020 Seon Rozenblum, Unexpected Maker
|
||||
#
|
||||
# Project home:
|
||||
# https://feathers2.io
|
||||
#
|
||||
|
||||
# Import required libraries
|
||||
import time
|
||||
import board
|
||||
from digitalio import DigitalInOut, Direction, Pull
|
||||
|
||||
|
||||
# Helper functions
|
||||
|
||||
def enable_LDO2(state):
|
||||
"""Set the power for the second on-board LDO to allow no current draw when not needed."""
|
||||
|
||||
# Grab a reference to the LDO2 IO (21 in this case)
|
||||
ldo2 = DigitalInOut(board.LDO2)
|
||||
ldo2.direction = Direction.OUTPUT
|
||||
|
||||
# Set the LDO2 power pin on / off
|
||||
ldo2.value = state
|
||||
|
||||
# A small delay to let the IO change state
|
||||
time.sleep(0.035)
|
||||
|
||||
|
||||
# Dotstar rainbow colour wheel
|
||||
def dotstar_color_wheel(wheel_pos):
|
||||
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
|
||||
wheel_pos = wheel_pos % 255
|
||||
|
||||
if wheel_pos < 85:
|
||||
return 255 - wheel_pos * 3, 0, wheel_pos * 3
|
||||
elif wheel_pos < 170:
|
||||
wheel_pos -= 85
|
||||
return 0, wheel_pos * 3, 255 - wheel_pos * 3
|
||||
else:
|
||||
wheel_pos -= 170
|
||||
return wheel_pos * 3, 255 - wheel_pos * 3, 0
|
||||
|
||||
|
||||
|
||||
# Disable LDO2 by default
|
||||
enable_LDO2(False)
|
@ -35,6 +35,5 @@
|
||||
|
||||
#define AUTORESET_DELAY_MS 500
|
||||
|
||||
// Doesn't work with this on.
|
||||
// #define MICROPY_HW_APA102_MOSI (&pin_GPIO44)
|
||||
// #define MICROPY_HW_APA102_SCK (&pin_GPIO45)
|
||||
#define MICROPY_HW_APA102_MOSI (&pin_GPIO40)
|
||||
#define MICROPY_HW_APA102_SCK (&pin_GPIO45)
|
||||
|
@ -16,3 +16,7 @@ CIRCUITPY_ESP_FLASH_FREQ=40m
|
||||
CIRCUITPY_ESP_FLASH_SIZE=16MB
|
||||
|
||||
CIRCUITPY_BITBANG_APA102 = 1
|
||||
|
||||
# Include these Python libraries in firmware.
|
||||
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DotStar
|
||||
|
||||
|
@ -1,55 +1,103 @@
|
||||
#include "shared-bindings/board/__init__.h"
|
||||
|
||||
STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO17) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO18) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO18) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO14) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO14) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO13) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO13) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO12) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO6) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO6) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO5) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO36) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO35) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO37) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO44) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO43) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
|
||||
|
||||
// Moving to 9 and 8
|
||||
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO38) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO33) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO9) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO11) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_GPIO44) }, // MTDO
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO9) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO9) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO0) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A10), MP_ROM_PTR(&pin_GPIO1) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_GPIO3) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_GPIO7) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO33) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO38) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO10) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO11) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO11) },
|
||||
|
||||
// { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, // MTDO
|
||||
{ MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_GPIO40) }, // MTDO
|
||||
|
||||
// { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_GPIO45) },
|
||||
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_LDO2), MP_ROM_PTR(&pin_GPIO21) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AMB), MP_ROM_PTR(&pin_GPIO4) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
|
||||
|
198
ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/adafruit_dotstar.py
Executable file
198
ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/adafruit_dotstar.py
Executable file
@ -0,0 +1,198 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2016 Damien P. George (original Neopixel object)
|
||||
# Copyright (c) 2017 Ladyada
|
||||
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
# Copyright (c) 2019 Roy Hooper
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
`adafruit_dotstar` - DotStar strip driver (for CircuitPython 5.0+ with _pixelbuf)
|
||||
=================================================================================
|
||||
|
||||
* Author(s): Damien P. George, Limor Fried, Scott Shawcroft & Roy Hooper
|
||||
"""
|
||||
|
||||
# pylint: disable=ungrouped-imports
|
||||
import sys
|
||||
import busio
|
||||
import digitalio
|
||||
|
||||
if sys.implementation.version[0] < 5:
|
||||
import adafruit_pypixelbuf as _pixelbuf
|
||||
else:
|
||||
try:
|
||||
import _pixelbuf
|
||||
except ImportError:
|
||||
import adafruit_pypixelbuf as _pixelbuf
|
||||
|
||||
__version__ = "0.0.0-auto.0"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git"
|
||||
|
||||
START_HEADER_SIZE = 4
|
||||
|
||||
# Pixel color order constants
|
||||
RBG = "PRBG"
|
||||
"""Red Blue Green"""
|
||||
RGB = "PRGB"
|
||||
"""Red Green Blue"""
|
||||
GRB = "PGRB"
|
||||
"""Green Red Blue"""
|
||||
GBR = "PGBR"
|
||||
"""Green Blue Red"""
|
||||
BRG = "PBRG"
|
||||
"""Blue Red Green"""
|
||||
BGR = "PBGR"
|
||||
"""Blue Green Red"""
|
||||
|
||||
|
||||
class DotStar(_pixelbuf.PixelBuf):
|
||||
"""
|
||||
A sequence of dotstars.
|
||||
|
||||
:param ~microcontroller.Pin clock: The pin to output dotstar clock on.
|
||||
:param ~microcontroller.Pin data: The pin to output dotstar data on.
|
||||
:param int n: The number of dotstars in the chain
|
||||
:param float brightness: Brightness of the pixels between 0.0 and 1.0
|
||||
:param bool auto_write: True if the dotstars should immediately change when
|
||||
set. If False, `show` must be called explicitly.
|
||||
:param str pixel_order: Set the pixel order on the strip - different
|
||||
strips implement this differently. If you send red, and it looks blue
|
||||
or green on the strip, modify this! It should be one of the values above.
|
||||
:param int baudrate: Desired clock rate if using hardware SPI (ignored if
|
||||
using 'soft' SPI). This is only a recommendation; the actual clock
|
||||
rate may be slightly different depending on what the system hardware
|
||||
can provide.
|
||||
|
||||
Example for Gemma M0:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import adafruit_dotstar
|
||||
import time
|
||||
from board import *
|
||||
|
||||
RED = 0x100000
|
||||
|
||||
with adafruit_dotstar.DotStar(APA102_SCK, APA102_MOSI, 1) as pixels:
|
||||
pixels[0] = RED
|
||||
time.sleep(2)
|
||||
|
||||
.. py:method:: DotStar.show()
|
||||
|
||||
Shows the new colors on the dotstars themselves if they haven't already
|
||||
been autowritten.
|
||||
|
||||
The colors may or may not be showing after this function returns because
|
||||
it may be done asynchronously.
|
||||
|
||||
.. py:method:: DotStar.fill(color)
|
||||
|
||||
Colors all dotstars the given ***color***.
|
||||
|
||||
.. py:attribute:: brightness
|
||||
|
||||
Overall brightness of all dotstars (0 to 1.0)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
clock,
|
||||
data,
|
||||
n,
|
||||
*,
|
||||
brightness=1.0,
|
||||
auto_write=True,
|
||||
pixel_order=BGR,
|
||||
baudrate=4000000
|
||||
):
|
||||
self._spi = None
|
||||
try:
|
||||
self._spi = busio.SPI(clock, MOSI=data)
|
||||
while not self._spi.try_lock():
|
||||
pass
|
||||
self._spi.configure(baudrate=baudrate)
|
||||
|
||||
except (NotImplementedError, ValueError):
|
||||
self.dpin = digitalio.DigitalInOut(data)
|
||||
self.cpin = digitalio.DigitalInOut(clock)
|
||||
self.dpin.direction = digitalio.Direction.OUTPUT
|
||||
self.cpin.direction = digitalio.Direction.OUTPUT
|
||||
self.cpin.value = False
|
||||
|
||||
# Supply one extra clock cycle for each two pixels in the strip.
|
||||
trailer_size = n // 16
|
||||
if n % 16 != 0:
|
||||
trailer_size += 1
|
||||
|
||||
# Four empty bytes for the header.
|
||||
header = bytearray(START_HEADER_SIZE)
|
||||
# 0xff bytes for the trailer.
|
||||
trailer = bytearray(b"\xff") * trailer_size
|
||||
|
||||
super().__init__(
|
||||
n,
|
||||
byteorder=pixel_order,
|
||||
brightness=brightness,
|
||||
auto_write=auto_write,
|
||||
header=header,
|
||||
trailer=trailer,
|
||||
)
|
||||
|
||||
def deinit(self):
|
||||
"""Blank out the DotStars and release the resources."""
|
||||
self.fill(0)
|
||||
self.show()
|
||||
if self._spi:
|
||||
self._spi.deinit()
|
||||
else:
|
||||
self.dpin.deinit()
|
||||
self.cpin.deinit()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
self.deinit()
|
||||
|
||||
def __repr__(self):
|
||||
return "[" + ", ".join([str(x) for x in self]) + "]"
|
||||
|
||||
@property
|
||||
def n(self):
|
||||
"""
|
||||
The number of dotstars in the chain (read-only)
|
||||
"""
|
||||
return len(self)
|
||||
|
||||
def _transmit(self, buffer):
|
||||
if self._spi:
|
||||
self._spi.write(buffer)
|
||||
else:
|
||||
self._ds_writebytes(buffer)
|
||||
|
||||
def _ds_writebytes(self, buffer):
|
||||
for b in buffer:
|
||||
for _ in range(8):
|
||||
self.dpin.value = b & 0x80
|
||||
self.cpin.value = True
|
||||
self.cpin.value = False
|
||||
b = b << 1
|
||||
self.cpin.value = False
|
374
ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/adafruit_pypixelbuf.py
Executable file
374
ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/adafruit_pypixelbuf.py
Executable file
@ -0,0 +1,374 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Based on the Adafruit NeoPixel and Adafruit Dotstar CircuitPython drivers.
|
||||
# Copyright (c) 2019-2020 Roy Hooper
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
`adafruit_pypixelbuf` - A pure python implementation of _pixelbuf
|
||||
=================================================================
|
||||
This class is used when _pixelbuf is not available in CircuitPython. It is based on the work
|
||||
in neopixel.py and adafruit_dotstar.py.
|
||||
|
||||
* Author(s): Damien P. George & Limor Fried & Scott Shawcroft & Roy Hooper
|
||||
"""
|
||||
|
||||
DOTSTAR_LED_START_FULL_BRIGHT = 0xFF
|
||||
DOTSTAR_LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits
|
||||
DOTSTAR_LED_BRIGHTNESS = 0b00011111
|
||||
|
||||
|
||||
class PixelBuf: # pylint: disable=too-many-instance-attributes
|
||||
"""
|
||||
A sequence of RGB/RGBW pixels.
|
||||
|
||||
This is the pure python implementation of CircuitPython's _pixelbuf.
|
||||
|
||||
:param ~int n: Number of pixels
|
||||
:param ~str byteorder: Byte order string constant (also sets bpp)
|
||||
:param ~float brightness: Brightness (0 to 1.0, default 1.0)
|
||||
:param ~bool auto_write: Whether to automatically write pixels (Default False)
|
||||
:param bytes header: Sequence of bytes to always send before pixel values.
|
||||
:param bytes trailer: Sequence of bytes to always send after pixel values.
|
||||
"""
|
||||
|
||||
def __init__( # pylint: disable=too-many-locals,too-many-arguments
|
||||
self,
|
||||
n,
|
||||
byteorder="BGR",
|
||||
brightness=1.0,
|
||||
auto_write=False,
|
||||
header=None,
|
||||
trailer=None,
|
||||
):
|
||||
|
||||
bpp, byteorder_tuple, has_white, dotstar_mode = self.parse_byteorder(byteorder)
|
||||
|
||||
self.auto_write = False
|
||||
|
||||
effective_bpp = 4 if dotstar_mode else bpp
|
||||
_bytes = effective_bpp * n
|
||||
buf = bytearray(_bytes)
|
||||
offset = 0
|
||||
|
||||
if header is not None:
|
||||
if not isinstance(header, bytearray):
|
||||
raise TypeError("header must be a bytearray")
|
||||
buf = header + buf
|
||||
offset = len(header)
|
||||
|
||||
if trailer is not None:
|
||||
if not isinstance(trailer, bytearray):
|
||||
raise TypeError("trailer must be a bytearray")
|
||||
buf += trailer
|
||||
|
||||
self._pixels = n
|
||||
self._bytes = _bytes
|
||||
self._byteorder = byteorder_tuple
|
||||
self._byteorder_string = byteorder
|
||||
self._has_white = has_white
|
||||
self._bpp = bpp
|
||||
self._pre_brightness_buffer = None
|
||||
self._post_brightness_buffer = buf
|
||||
self._offset = offset
|
||||
self._dotstar_mode = dotstar_mode
|
||||
self._pixel_step = effective_bpp
|
||||
|
||||
if dotstar_mode:
|
||||
self._byteorder_tuple = (
|
||||
byteorder_tuple[0] + 1,
|
||||
byteorder_tuple[1] + 1,
|
||||
byteorder_tuple[2] + 1,
|
||||
0,
|
||||
)
|
||||
# Initialize the buffer with the dotstar start bytes.
|
||||
for i in range(self._offset, self._bytes + self._offset, 4):
|
||||
self._post_brightness_buffer[i] = DOTSTAR_LED_START_FULL_BRIGHT
|
||||
|
||||
self._brightness = 1.0
|
||||
self.brightness = brightness
|
||||
|
||||
self.auto_write = auto_write
|
||||
|
||||
@staticmethod
|
||||
def parse_byteorder(byteorder):
|
||||
"""
|
||||
Parse a Byteorder string for validity and determine bpp, byte order, and
|
||||
dostar brightness bits.
|
||||
|
||||
Byteorder strings may contain the following characters:
|
||||
R - Red
|
||||
G - Green
|
||||
B - Blue
|
||||
W - White
|
||||
P - PWM (PWM Duty cycle for pixel - dotstars 0 - 1.0)
|
||||
|
||||
:param: ~str bpp: bpp string.
|
||||
:return: ~tuple: bpp, byteorder, has_white, dotstar_mode
|
||||
"""
|
||||
bpp = len(byteorder)
|
||||
dotstar_mode = False
|
||||
has_white = False
|
||||
|
||||
if byteorder.strip("RGBWP") != "":
|
||||
raise ValueError("Invalid Byteorder string")
|
||||
|
||||
try:
|
||||
r = byteorder.index("R")
|
||||
g = byteorder.index("G")
|
||||
b = byteorder.index("B")
|
||||
except ValueError:
|
||||
raise ValueError("Invalid Byteorder string")
|
||||
if "W" in byteorder:
|
||||
w = byteorder.index("W")
|
||||
byteorder = (r, g, b, w)
|
||||
has_white = True
|
||||
elif "P" in byteorder:
|
||||
lum = byteorder.index("P")
|
||||
byteorder = (r, g, b, lum)
|
||||
dotstar_mode = True
|
||||
else:
|
||||
byteorder = (r, g, b)
|
||||
|
||||
return bpp, byteorder, has_white, dotstar_mode
|
||||
|
||||
@property
|
||||
def bpp(self):
|
||||
"""
|
||||
The number of bytes per pixel in the buffer (read-only).
|
||||
"""
|
||||
return self._bpp
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""
|
||||
Float value between 0 and 1. Output brightness.
|
||||
|
||||
When brightness is less than 1.0, a second buffer will be used to store the color values
|
||||
before they are adjusted for brightness.
|
||||
"""
|
||||
return self._brightness
|
||||
|
||||
@brightness.setter
|
||||
def brightness(self, value):
|
||||
value = min(max(value, 0.0), 1.0)
|
||||
change = value - self._brightness
|
||||
if -0.001 < change < 0.001:
|
||||
return
|
||||
|
||||
self._brightness = value
|
||||
|
||||
if self._pre_brightness_buffer is None:
|
||||
self._pre_brightness_buffer = bytearray(self._post_brightness_buffer)
|
||||
|
||||
# Adjust brightness of existing pixels
|
||||
offset_check = self._offset % self._pixel_step
|
||||
for i in range(self._offset, self._bytes + self._offset):
|
||||
# Don't adjust per-pixel luminance bytes in dotstar mode
|
||||
if self._dotstar_mode and (i % 4 != offset_check):
|
||||
continue
|
||||
self._post_brightness_buffer[i] = int(
|
||||
self._pre_brightness_buffer[i] * self._brightness
|
||||
)
|
||||
|
||||
if self.auto_write:
|
||||
self.show()
|
||||
|
||||
@property
|
||||
def byteorder(self):
|
||||
"""
|
||||
ByteOrder string for the buffer (read-only)
|
||||
"""
|
||||
return self._byteorder_string
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Number of pixels.
|
||||
"""
|
||||
return self._pixels
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
Call the associated write function to display the pixels
|
||||
"""
|
||||
return self._transmit(self._post_brightness_buffer)
|
||||
|
||||
def fill(self, color):
|
||||
"""
|
||||
Fills the given pixelbuf with the given color.
|
||||
:param pixelbuf: A pixel object.
|
||||
:param color: Color to set.
|
||||
"""
|
||||
r, g, b, w = self._parse_color(color)
|
||||
for i in range(self._pixels):
|
||||
self._set_item(i, r, g, b, w)
|
||||
if self.auto_write:
|
||||
self.show()
|
||||
|
||||
def _parse_color(self, value):
|
||||
r = 0
|
||||
g = 0
|
||||
b = 0
|
||||
w = 0
|
||||
if isinstance(value, int):
|
||||
r = value >> 16
|
||||
g = (value >> 8) & 0xFF
|
||||
b = value & 0xFF
|
||||
w = 0
|
||||
|
||||
if self._dotstar_mode:
|
||||
w = 1.0
|
||||
else:
|
||||
if len(value) < 3 or len(value) > 4:
|
||||
raise ValueError(
|
||||
"Expected tuple of length {}, got {}".format(self._bpp, len(value))
|
||||
)
|
||||
if len(value) == self._bpp:
|
||||
if self._bpp == 3:
|
||||
r, g, b = value
|
||||
else:
|
||||
r, g, b, w = value
|
||||
elif len(value) == 3:
|
||||
r, g, b = value
|
||||
if self._dotstar_mode:
|
||||
w = 1.0
|
||||
|
||||
if self._bpp == 4:
|
||||
if self._dotstar_mode:
|
||||
# LED startframe is three "1" bits, followed by 5 brightness bits
|
||||
# then 8 bits for each of R, G, and B. The order of those 3 are configurable and
|
||||
# vary based on hardware
|
||||
w = (int(w * 31) & 0b00011111) | DOTSTAR_LED_START
|
||||
elif (
|
||||
self._has_white
|
||||
and (isinstance(value, int) or len(value) == 3)
|
||||
and r == g
|
||||
and g == b
|
||||
):
|
||||
# If all components are the same and we have a white pixel then use it
|
||||
# instead of the individual components when all 4 values aren't explicitly given.
|
||||
w = r
|
||||
r = 0
|
||||
g = 0
|
||||
b = 0
|
||||
|
||||
return (r, g, b, w)
|
||||
|
||||
def _set_item(
|
||||
self, index, r, g, b, w
|
||||
): # pylint: disable=too-many-locals,too-many-branches,too-many-arguments
|
||||
if index < 0:
|
||||
index += len(self)
|
||||
if index >= self._pixels or index < 0:
|
||||
raise IndexError
|
||||
offset = self._offset + (index * self._bpp)
|
||||
|
||||
if self._pre_brightness_buffer is not None:
|
||||
if self._bpp == 4:
|
||||
self._pre_brightness_buffer[offset + self._byteorder[3]] = w
|
||||
self._pre_brightness_buffer[offset + self._byteorder[0]] = r
|
||||
self._pre_brightness_buffer[offset + self._byteorder[1]] = g
|
||||
self._pre_brightness_buffer[offset + self._byteorder[2]] = b
|
||||
|
||||
if self._bpp == 4:
|
||||
# Only apply brightness if w is actually white (aka not DotStar.)
|
||||
if not self._dotstar_mode:
|
||||
w = int(w * self._brightness)
|
||||
self._post_brightness_buffer[offset + self._byteorder[3]] = w
|
||||
|
||||
self._post_brightness_buffer[offset + self._byteorder[0]] = int(
|
||||
r * self._brightness
|
||||
)
|
||||
self._post_brightness_buffer[offset + self._byteorder[1]] = int(
|
||||
g * self._brightness
|
||||
)
|
||||
self._post_brightness_buffer[offset + self._byteorder[2]] = int(
|
||||
b * self._brightness
|
||||
)
|
||||
|
||||
def __setitem__(self, index, val):
|
||||
if isinstance(index, slice):
|
||||
start, stop, step = index.indices(self._pixels)
|
||||
for val_i, in_i in enumerate(range(start, stop, step)):
|
||||
r, g, b, w = self._parse_color(val[val_i])
|
||||
self._set_item(in_i, r, g, b, w)
|
||||
else:
|
||||
r, g, b, w = self._parse_color(val)
|
||||
self._set_item(index, r, g, b, w)
|
||||
|
||||
if self.auto_write:
|
||||
self.show()
|
||||
|
||||
def _getitem(self, index):
|
||||
start = self._offset + (index * self._bpp)
|
||||
buffer = (
|
||||
self._pre_brightness_buffer
|
||||
if self._pre_brightness_buffer is not None
|
||||
else self._post_brightness_buffer
|
||||
)
|
||||
value = [
|
||||
buffer[start + self._byteorder[0]],
|
||||
buffer[start + self._byteorder[1]],
|
||||
buffer[start + self._byteorder[2]],
|
||||
]
|
||||
if self._has_white:
|
||||
value.append(buffer[start + self._byteorder[3]])
|
||||
elif self._dotstar_mode:
|
||||
value.append(
|
||||
(buffer[start + self._byteorder[3]] & DOTSTAR_LED_BRIGHTNESS) / 31.0
|
||||
)
|
||||
return value
|
||||
|
||||
def __getitem__(self, index):
|
||||
if isinstance(index, slice):
|
||||
out = []
|
||||
for in_i in range(
|
||||
*index.indices(len(self._post_brightness_buffer) // self._bpp)
|
||||
):
|
||||
out.append(self._getitem(in_i))
|
||||
return out
|
||||
if index < 0:
|
||||
index += len(self)
|
||||
if index >= self._pixels or index < 0:
|
||||
raise IndexError
|
||||
return self._getitem(index)
|
||||
|
||||
def _transmit(self, buffer):
|
||||
raise NotImplementedError("Must be subclassed")
|
||||
|
||||
|
||||
def wheel(pos):
|
||||
"""
|
||||
Helper to create a colorwheel.
|
||||
|
||||
:param pos: int 0-255 of color value to return
|
||||
:return: tuple of RGB values
|
||||
"""
|
||||
# Input a value 0 to 255 to get a color value.
|
||||
# The colours are a transition r - g - b - back to r.
|
||||
if pos < 0 or pos > 255:
|
||||
return 0, 0, 0
|
||||
if pos < 85:
|
||||
return 255 - pos * 3, pos * 3, 0
|
||||
if pos < 170:
|
||||
pos -= 85
|
||||
return 0, 255 - pos * 3, pos * 3
|
||||
pos -= 170
|
||||
return pos * 3, 0, 255 - pos * 3
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "boards/board.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
|
||||
void board_init(void) {
|
||||
// USB
|
||||
common_hal_never_reset_pin(&pin_GPIO19);
|
||||
common_hal_never_reset_pin(&pin_GPIO20);
|
||||
|
||||
// Debug UART
|
||||
common_hal_never_reset_pin(&pin_GPIO43);
|
||||
common_hal_never_reset_pin(&pin_GPIO44);
|
||||
|
||||
// SPI Flash and RAM
|
||||
common_hal_never_reset_pin(&pin_GPIO26);
|
||||
common_hal_never_reset_pin(&pin_GPIO27);
|
||||
common_hal_never_reset_pin(&pin_GPIO28);
|
||||
common_hal_never_reset_pin(&pin_GPIO29);
|
||||
common_hal_never_reset_pin(&pin_GPIO30);
|
||||
common_hal_never_reset_pin(&pin_GPIO31);
|
||||
common_hal_never_reset_pin(&pin_GPIO32);
|
||||
}
|
||||
|
||||
bool board_requests_safe_mode(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void reset_board(void) {
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
# FeatherS2 Helper Library
|
||||
# 2020 Seon Rozenblum, Unexpected Maker
|
||||
#
|
||||
# Project home:
|
||||
# https://feathers2.io
|
||||
#
|
||||
|
||||
# Import required libraries
|
||||
import time
|
||||
import board
|
||||
from digitalio import DigitalInOut, Direction, Pull
|
||||
|
||||
|
||||
# Helper functions
|
||||
|
||||
def enable_LDO2(state):
|
||||
"""Set the power for the second on-board LDO to allow no current draw when not needed."""
|
||||
|
||||
# Grab a reference to the LDO2 IO (21 in this case)
|
||||
ldo2 = DigitalInOut(board.LDO2)
|
||||
ldo2.direction = Direction.OUTPUT
|
||||
|
||||
# Set the LDO2 power pin on / off
|
||||
ldo2.value = state
|
||||
|
||||
# A small delay to let the IO change state
|
||||
time.sleep(0.035)
|
||||
|
||||
|
||||
# Dotstar rainbow colour wheel
|
||||
def dotstar_color_wheel(wheel_pos):
|
||||
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
|
||||
wheel_pos = wheel_pos % 255
|
||||
|
||||
if wheel_pos < 85:
|
||||
return 255 - wheel_pos * 3, 0, wheel_pos * 3
|
||||
elif wheel_pos < 170:
|
||||
wheel_pos -= 85
|
||||
return 0, wheel_pos * 3, 255 - wheel_pos * 3
|
||||
else:
|
||||
wheel_pos -= 170
|
||||
return wheel_pos * 3, 255 - wheel_pos * 3, 0
|
||||
|
||||
|
||||
|
||||
# Disable LDO2 by default
|
||||
enable_LDO2(False)
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
//Micropython setup
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "FeatherS2"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32S2"
|
||||
|
||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
|
||||
|
||||
#define BOARD_USER_SAFE_MODE_ACTION "pressing boot button at start up.\n"
|
||||
|
||||
#define AUTORESET_DELAY_MS 500
|
||||
|
||||
// Doesn't work with this on.
|
||||
// #define MICROPY_HW_APA102_MOSI (&pin_GPIO44)
|
||||
// #define MICROPY_HW_APA102_SCK (&pin_GPIO45)
|
@ -0,0 +1,21 @@
|
||||
USB_VID = 0x239A
|
||||
USB_PID = 0x80AC
|
||||
USB_PRODUCT = "FeatherS2"
|
||||
USB_MANUFACTURER = "UnexpectedMaker"
|
||||
USB_DEVICES = "CDC,MSC,HID"
|
||||
|
||||
INTERNAL_FLASH_FILESYSTEM = 1
|
||||
LONGINT_IMPL = MPZ
|
||||
|
||||
# The default queue depth of 16 overflows on release builds,
|
||||
# so increase it to 32.
|
||||
CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
|
||||
|
||||
CIRCUITPY_ESP_FLASH_MODE=qio
|
||||
CIRCUITPY_ESP_FLASH_FREQ=40m
|
||||
CIRCUITPY_ESP_FLASH_SIZE=16MB
|
||||
|
||||
CIRCUITPY_BITBANG_APA102 = 1
|
||||
|
||||
# Include these Python libraries in firmware.
|
||||
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DotStar
|
@ -0,0 +1,56 @@
|
||||
#include "shared-bindings/board/__init__.h"
|
||||
|
||||
STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO17) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO18) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO18) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO12) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO6) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO6) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO5) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO36) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO35) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO37) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO44) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO43) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
|
||||
|
||||
// Moving to 9 and 8
|
||||
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO38) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO33) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO9) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO11) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_GPIO40) }, // MTDO
|
||||
{ MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_GPIO45) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LDO2), MP_ROM_PTR(&pin_GPIO21) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AMB), MP_ROM_PTR(&pin_GPIO4) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
|
||||
};
|
||||
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
|
@ -0,0 +1,35 @@
|
||||
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
|
||||
|
||||
#
|
||||
# SPI RAM config
|
||||
#
|
||||
# CONFIG_SPIRAM_TYPE_AUTO is not set
|
||||
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
|
||||
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
|
||||
CONFIG_SPIRAM_TYPE_ESPPSRAM64=y
|
||||
CONFIG_SPIRAM_SIZE=8388608
|
||||
|
||||
#
|
||||
# PSRAM clock and cs IO for ESP32S2
|
||||
#
|
||||
CONFIG_DEFAULT_PSRAM_CLK_IO=30
|
||||
CONFIG_DEFAULT_PSRAM_CS_IO=26
|
||||
# end of PSRAM clock and cs IO for ESP32S2
|
||||
|
||||
CONFIG_SPIRAM_SPIWP_SD3_PIN=28
|
||||
# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
|
||||
# CONFIG_SPIRAM_RODATA is not set
|
||||
# CONFIG_SPIRAM_USE_AHB_DBUS3 is not set
|
||||
# CONFIG_SPIRAM_SPEED_80M is not set
|
||||
CONFIG_SPIRAM_SPEED_40M=y
|
||||
# CONFIG_SPIRAM_SPEED_26M is not set
|
||||
# CONFIG_SPIRAM_SPEED_20M is not set
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_BOOT_INIT=y
|
||||
# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
|
||||
CONFIG_SPIRAM_USE_MEMMAP=y
|
||||
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
|
||||
# CONFIG_SPIRAM_USE_MALLOC is not set
|
||||
CONFIG_SPIRAM_MEMTEST=y
|
||||
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
|
||||
# end of SPI RAM config
|
198
ports/esp32s2/boards/unexpectedmaker_pros2/adafruit_dotstar.py
Executable file
198
ports/esp32s2/boards/unexpectedmaker_pros2/adafruit_dotstar.py
Executable file
@ -0,0 +1,198 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2016 Damien P. George (original Neopixel object)
|
||||
# Copyright (c) 2017 Ladyada
|
||||
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
# Copyright (c) 2019 Roy Hooper
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
`adafruit_dotstar` - DotStar strip driver (for CircuitPython 5.0+ with _pixelbuf)
|
||||
=================================================================================
|
||||
|
||||
* Author(s): Damien P. George, Limor Fried, Scott Shawcroft & Roy Hooper
|
||||
"""
|
||||
|
||||
# pylint: disable=ungrouped-imports
|
||||
import sys
|
||||
import busio
|
||||
import digitalio
|
||||
|
||||
if sys.implementation.version[0] < 5:
|
||||
import adafruit_pypixelbuf as _pixelbuf
|
||||
else:
|
||||
try:
|
||||
import _pixelbuf
|
||||
except ImportError:
|
||||
import adafruit_pypixelbuf as _pixelbuf
|
||||
|
||||
__version__ = "0.0.0-auto.0"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git"
|
||||
|
||||
START_HEADER_SIZE = 4
|
||||
|
||||
# Pixel color order constants
|
||||
RBG = "PRBG"
|
||||
"""Red Blue Green"""
|
||||
RGB = "PRGB"
|
||||
"""Red Green Blue"""
|
||||
GRB = "PGRB"
|
||||
"""Green Red Blue"""
|
||||
GBR = "PGBR"
|
||||
"""Green Blue Red"""
|
||||
BRG = "PBRG"
|
||||
"""Blue Red Green"""
|
||||
BGR = "PBGR"
|
||||
"""Blue Green Red"""
|
||||
|
||||
|
||||
class DotStar(_pixelbuf.PixelBuf):
|
||||
"""
|
||||
A sequence of dotstars.
|
||||
|
||||
:param ~microcontroller.Pin clock: The pin to output dotstar clock on.
|
||||
:param ~microcontroller.Pin data: The pin to output dotstar data on.
|
||||
:param int n: The number of dotstars in the chain
|
||||
:param float brightness: Brightness of the pixels between 0.0 and 1.0
|
||||
:param bool auto_write: True if the dotstars should immediately change when
|
||||
set. If False, `show` must be called explicitly.
|
||||
:param str pixel_order: Set the pixel order on the strip - different
|
||||
strips implement this differently. If you send red, and it looks blue
|
||||
or green on the strip, modify this! It should be one of the values above.
|
||||
:param int baudrate: Desired clock rate if using hardware SPI (ignored if
|
||||
using 'soft' SPI). This is only a recommendation; the actual clock
|
||||
rate may be slightly different depending on what the system hardware
|
||||
can provide.
|
||||
|
||||
Example for Gemma M0:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import adafruit_dotstar
|
||||
import time
|
||||
from board import *
|
||||
|
||||
RED = 0x100000
|
||||
|
||||
with adafruit_dotstar.DotStar(APA102_SCK, APA102_MOSI, 1) as pixels:
|
||||
pixels[0] = RED
|
||||
time.sleep(2)
|
||||
|
||||
.. py:method:: DotStar.show()
|
||||
|
||||
Shows the new colors on the dotstars themselves if they haven't already
|
||||
been autowritten.
|
||||
|
||||
The colors may or may not be showing after this function returns because
|
||||
it may be done asynchronously.
|
||||
|
||||
.. py:method:: DotStar.fill(color)
|
||||
|
||||
Colors all dotstars the given ***color***.
|
||||
|
||||
.. py:attribute:: brightness
|
||||
|
||||
Overall brightness of all dotstars (0 to 1.0)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
clock,
|
||||
data,
|
||||
n,
|
||||
*,
|
||||
brightness=1.0,
|
||||
auto_write=True,
|
||||
pixel_order=BGR,
|
||||
baudrate=4000000
|
||||
):
|
||||
self._spi = None
|
||||
try:
|
||||
self._spi = busio.SPI(clock, MOSI=data)
|
||||
while not self._spi.try_lock():
|
||||
pass
|
||||
self._spi.configure(baudrate=baudrate)
|
||||
|
||||
except (NotImplementedError, ValueError):
|
||||
self.dpin = digitalio.DigitalInOut(data)
|
||||
self.cpin = digitalio.DigitalInOut(clock)
|
||||
self.dpin.direction = digitalio.Direction.OUTPUT
|
||||
self.cpin.direction = digitalio.Direction.OUTPUT
|
||||
self.cpin.value = False
|
||||
|
||||
# Supply one extra clock cycle for each two pixels in the strip.
|
||||
trailer_size = n // 16
|
||||
if n % 16 != 0:
|
||||
trailer_size += 1
|
||||
|
||||
# Four empty bytes for the header.
|
||||
header = bytearray(START_HEADER_SIZE)
|
||||
# 0xff bytes for the trailer.
|
||||
trailer = bytearray(b"\xff") * trailer_size
|
||||
|
||||
super().__init__(
|
||||
n,
|
||||
byteorder=pixel_order,
|
||||
brightness=brightness,
|
||||
auto_write=auto_write,
|
||||
header=header,
|
||||
trailer=trailer,
|
||||
)
|
||||
|
||||
def deinit(self):
|
||||
"""Blank out the DotStars and release the resources."""
|
||||
self.fill(0)
|
||||
self.show()
|
||||
if self._spi:
|
||||
self._spi.deinit()
|
||||
else:
|
||||
self.dpin.deinit()
|
||||
self.cpin.deinit()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
self.deinit()
|
||||
|
||||
def __repr__(self):
|
||||
return "[" + ", ".join([str(x) for x in self]) + "]"
|
||||
|
||||
@property
|
||||
def n(self):
|
||||
"""
|
||||
The number of dotstars in the chain (read-only)
|
||||
"""
|
||||
return len(self)
|
||||
|
||||
def _transmit(self, buffer):
|
||||
if self._spi:
|
||||
self._spi.write(buffer)
|
||||
else:
|
||||
self._ds_writebytes(buffer)
|
||||
|
||||
def _ds_writebytes(self, buffer):
|
||||
for b in buffer:
|
||||
for _ in range(8):
|
||||
self.dpin.value = b & 0x80
|
||||
self.cpin.value = True
|
||||
self.cpin.value = False
|
||||
b = b << 1
|
||||
self.cpin.value = False
|
374
ports/esp32s2/boards/unexpectedmaker_pros2/adafruit_pypixelbuf.py
Executable file
374
ports/esp32s2/boards/unexpectedmaker_pros2/adafruit_pypixelbuf.py
Executable file
@ -0,0 +1,374 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Based on the Adafruit NeoPixel and Adafruit Dotstar CircuitPython drivers.
|
||||
# Copyright (c) 2019-2020 Roy Hooper
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
`adafruit_pypixelbuf` - A pure python implementation of _pixelbuf
|
||||
=================================================================
|
||||
This class is used when _pixelbuf is not available in CircuitPython. It is based on the work
|
||||
in neopixel.py and adafruit_dotstar.py.
|
||||
|
||||
* Author(s): Damien P. George & Limor Fried & Scott Shawcroft & Roy Hooper
|
||||
"""
|
||||
|
||||
DOTSTAR_LED_START_FULL_BRIGHT = 0xFF
|
||||
DOTSTAR_LED_START = 0b11100000 # Three "1" bits, followed by 5 brightness bits
|
||||
DOTSTAR_LED_BRIGHTNESS = 0b00011111
|
||||
|
||||
|
||||
class PixelBuf: # pylint: disable=too-many-instance-attributes
|
||||
"""
|
||||
A sequence of RGB/RGBW pixels.
|
||||
|
||||
This is the pure python implementation of CircuitPython's _pixelbuf.
|
||||
|
||||
:param ~int n: Number of pixels
|
||||
:param ~str byteorder: Byte order string constant (also sets bpp)
|
||||
:param ~float brightness: Brightness (0 to 1.0, default 1.0)
|
||||
:param ~bool auto_write: Whether to automatically write pixels (Default False)
|
||||
:param bytes header: Sequence of bytes to always send before pixel values.
|
||||
:param bytes trailer: Sequence of bytes to always send after pixel values.
|
||||
"""
|
||||
|
||||
def __init__( # pylint: disable=too-many-locals,too-many-arguments
|
||||
self,
|
||||
n,
|
||||
byteorder="BGR",
|
||||
brightness=1.0,
|
||||
auto_write=False,
|
||||
header=None,
|
||||
trailer=None,
|
||||
):
|
||||
|
||||
bpp, byteorder_tuple, has_white, dotstar_mode = self.parse_byteorder(byteorder)
|
||||
|
||||
self.auto_write = False
|
||||
|
||||
effective_bpp = 4 if dotstar_mode else bpp
|
||||
_bytes = effective_bpp * n
|
||||
buf = bytearray(_bytes)
|
||||
offset = 0
|
||||
|
||||
if header is not None:
|
||||
if not isinstance(header, bytearray):
|
||||
raise TypeError("header must be a bytearray")
|
||||
buf = header + buf
|
||||
offset = len(header)
|
||||
|
||||
if trailer is not None:
|
||||
if not isinstance(trailer, bytearray):
|
||||
raise TypeError("trailer must be a bytearray")
|
||||
buf += trailer
|
||||
|
||||
self._pixels = n
|
||||
self._bytes = _bytes
|
||||
self._byteorder = byteorder_tuple
|
||||
self._byteorder_string = byteorder
|
||||
self._has_white = has_white
|
||||
self._bpp = bpp
|
||||
self._pre_brightness_buffer = None
|
||||
self._post_brightness_buffer = buf
|
||||
self._offset = offset
|
||||
self._dotstar_mode = dotstar_mode
|
||||
self._pixel_step = effective_bpp
|
||||
|
||||
if dotstar_mode:
|
||||
self._byteorder_tuple = (
|
||||
byteorder_tuple[0] + 1,
|
||||
byteorder_tuple[1] + 1,
|
||||
byteorder_tuple[2] + 1,
|
||||
0,
|
||||
)
|
||||
# Initialize the buffer with the dotstar start bytes.
|
||||
for i in range(self._offset, self._bytes + self._offset, 4):
|
||||
self._post_brightness_buffer[i] = DOTSTAR_LED_START_FULL_BRIGHT
|
||||
|
||||
self._brightness = 1.0
|
||||
self.brightness = brightness
|
||||
|
||||
self.auto_write = auto_write
|
||||
|
||||
@staticmethod
|
||||
def parse_byteorder(byteorder):
|
||||
"""
|
||||
Parse a Byteorder string for validity and determine bpp, byte order, and
|
||||
dostar brightness bits.
|
||||
|
||||
Byteorder strings may contain the following characters:
|
||||
R - Red
|
||||
G - Green
|
||||
B - Blue
|
||||
W - White
|
||||
P - PWM (PWM Duty cycle for pixel - dotstars 0 - 1.0)
|
||||
|
||||
:param: ~str bpp: bpp string.
|
||||
:return: ~tuple: bpp, byteorder, has_white, dotstar_mode
|
||||
"""
|
||||
bpp = len(byteorder)
|
||||
dotstar_mode = False
|
||||
has_white = False
|
||||
|
||||
if byteorder.strip("RGBWP") != "":
|
||||
raise ValueError("Invalid Byteorder string")
|
||||
|
||||
try:
|
||||
r = byteorder.index("R")
|
||||
g = byteorder.index("G")
|
||||
b = byteorder.index("B")
|
||||
except ValueError:
|
||||
raise ValueError("Invalid Byteorder string")
|
||||
if "W" in byteorder:
|
||||
w = byteorder.index("W")
|
||||
byteorder = (r, g, b, w)
|
||||
has_white = True
|
||||
elif "P" in byteorder:
|
||||
lum = byteorder.index("P")
|
||||
byteorder = (r, g, b, lum)
|
||||
dotstar_mode = True
|
||||
else:
|
||||
byteorder = (r, g, b)
|
||||
|
||||
return bpp, byteorder, has_white, dotstar_mode
|
||||
|
||||
@property
|
||||
def bpp(self):
|
||||
"""
|
||||
The number of bytes per pixel in the buffer (read-only).
|
||||
"""
|
||||
return self._bpp
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""
|
||||
Float value between 0 and 1. Output brightness.
|
||||
|
||||
When brightness is less than 1.0, a second buffer will be used to store the color values
|
||||
before they are adjusted for brightness.
|
||||
"""
|
||||
return self._brightness
|
||||
|
||||
@brightness.setter
|
||||
def brightness(self, value):
|
||||
value = min(max(value, 0.0), 1.0)
|
||||
change = value - self._brightness
|
||||
if -0.001 < change < 0.001:
|
||||
return
|
||||
|
||||
self._brightness = value
|
||||
|
||||
if self._pre_brightness_buffer is None:
|
||||
self._pre_brightness_buffer = bytearray(self._post_brightness_buffer)
|
||||
|
||||
# Adjust brightness of existing pixels
|
||||
offset_check = self._offset % self._pixel_step
|
||||
for i in range(self._offset, self._bytes + self._offset):
|
||||
# Don't adjust per-pixel luminance bytes in dotstar mode
|
||||
if self._dotstar_mode and (i % 4 != offset_check):
|
||||
continue
|
||||
self._post_brightness_buffer[i] = int(
|
||||
self._pre_brightness_buffer[i] * self._brightness
|
||||
)
|
||||
|
||||
if self.auto_write:
|
||||
self.show()
|
||||
|
||||
@property
|
||||
def byteorder(self):
|
||||
"""
|
||||
ByteOrder string for the buffer (read-only)
|
||||
"""
|
||||
return self._byteorder_string
|
||||
|
||||
def __len__(self):
|
||||
"""
|
||||
Number of pixels.
|
||||
"""
|
||||
return self._pixels
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
Call the associated write function to display the pixels
|
||||
"""
|
||||
return self._transmit(self._post_brightness_buffer)
|
||||
|
||||
def fill(self, color):
|
||||
"""
|
||||
Fills the given pixelbuf with the given color.
|
||||
:param pixelbuf: A pixel object.
|
||||
:param color: Color to set.
|
||||
"""
|
||||
r, g, b, w = self._parse_color(color)
|
||||
for i in range(self._pixels):
|
||||
self._set_item(i, r, g, b, w)
|
||||
if self.auto_write:
|
||||
self.show()
|
||||
|
||||
def _parse_color(self, value):
|
||||
r = 0
|
||||
g = 0
|
||||
b = 0
|
||||
w = 0
|
||||
if isinstance(value, int):
|
||||
r = value >> 16
|
||||
g = (value >> 8) & 0xFF
|
||||
b = value & 0xFF
|
||||
w = 0
|
||||
|
||||
if self._dotstar_mode:
|
||||
w = 1.0
|
||||
else:
|
||||
if len(value) < 3 or len(value) > 4:
|
||||
raise ValueError(
|
||||
"Expected tuple of length {}, got {}".format(self._bpp, len(value))
|
||||
)
|
||||
if len(value) == self._bpp:
|
||||
if self._bpp == 3:
|
||||
r, g, b = value
|
||||
else:
|
||||
r, g, b, w = value
|
||||
elif len(value) == 3:
|
||||
r, g, b = value
|
||||
if self._dotstar_mode:
|
||||
w = 1.0
|
||||
|
||||
if self._bpp == 4:
|
||||
if self._dotstar_mode:
|
||||
# LED startframe is three "1" bits, followed by 5 brightness bits
|
||||
# then 8 bits for each of R, G, and B. The order of those 3 are configurable and
|
||||
# vary based on hardware
|
||||
w = (int(w * 31) & 0b00011111) | DOTSTAR_LED_START
|
||||
elif (
|
||||
self._has_white
|
||||
and (isinstance(value, int) or len(value) == 3)
|
||||
and r == g
|
||||
and g == b
|
||||
):
|
||||
# If all components are the same and we have a white pixel then use it
|
||||
# instead of the individual components when all 4 values aren't explicitly given.
|
||||
w = r
|
||||
r = 0
|
||||
g = 0
|
||||
b = 0
|
||||
|
||||
return (r, g, b, w)
|
||||
|
||||
def _set_item(
|
||||
self, index, r, g, b, w
|
||||
): # pylint: disable=too-many-locals,too-many-branches,too-many-arguments
|
||||
if index < 0:
|
||||
index += len(self)
|
||||
if index >= self._pixels or index < 0:
|
||||
raise IndexError
|
||||
offset = self._offset + (index * self._bpp)
|
||||
|
||||
if self._pre_brightness_buffer is not None:
|
||||
if self._bpp == 4:
|
||||
self._pre_brightness_buffer[offset + self._byteorder[3]] = w
|
||||
self._pre_brightness_buffer[offset + self._byteorder[0]] = r
|
||||
self._pre_brightness_buffer[offset + self._byteorder[1]] = g
|
||||
self._pre_brightness_buffer[offset + self._byteorder[2]] = b
|
||||
|
||||
if self._bpp == 4:
|
||||
# Only apply brightness if w is actually white (aka not DotStar.)
|
||||
if not self._dotstar_mode:
|
||||
w = int(w * self._brightness)
|
||||
self._post_brightness_buffer[offset + self._byteorder[3]] = w
|
||||
|
||||
self._post_brightness_buffer[offset + self._byteorder[0]] = int(
|
||||
r * self._brightness
|
||||
)
|
||||
self._post_brightness_buffer[offset + self._byteorder[1]] = int(
|
||||
g * self._brightness
|
||||
)
|
||||
self._post_brightness_buffer[offset + self._byteorder[2]] = int(
|
||||
b * self._brightness
|
||||
)
|
||||
|
||||
def __setitem__(self, index, val):
|
||||
if isinstance(index, slice):
|
||||
start, stop, step = index.indices(self._pixels)
|
||||
for val_i, in_i in enumerate(range(start, stop, step)):
|
||||
r, g, b, w = self._parse_color(val[val_i])
|
||||
self._set_item(in_i, r, g, b, w)
|
||||
else:
|
||||
r, g, b, w = self._parse_color(val)
|
||||
self._set_item(index, r, g, b, w)
|
||||
|
||||
if self.auto_write:
|
||||
self.show()
|
||||
|
||||
def _getitem(self, index):
|
||||
start = self._offset + (index * self._bpp)
|
||||
buffer = (
|
||||
self._pre_brightness_buffer
|
||||
if self._pre_brightness_buffer is not None
|
||||
else self._post_brightness_buffer
|
||||
)
|
||||
value = [
|
||||
buffer[start + self._byteorder[0]],
|
||||
buffer[start + self._byteorder[1]],
|
||||
buffer[start + self._byteorder[2]],
|
||||
]
|
||||
if self._has_white:
|
||||
value.append(buffer[start + self._byteorder[3]])
|
||||
elif self._dotstar_mode:
|
||||
value.append(
|
||||
(buffer[start + self._byteorder[3]] & DOTSTAR_LED_BRIGHTNESS) / 31.0
|
||||
)
|
||||
return value
|
||||
|
||||
def __getitem__(self, index):
|
||||
if isinstance(index, slice):
|
||||
out = []
|
||||
for in_i in range(
|
||||
*index.indices(len(self._post_brightness_buffer) // self._bpp)
|
||||
):
|
||||
out.append(self._getitem(in_i))
|
||||
return out
|
||||
if index < 0:
|
||||
index += len(self)
|
||||
if index >= self._pixels or index < 0:
|
||||
raise IndexError
|
||||
return self._getitem(index)
|
||||
|
||||
def _transmit(self, buffer):
|
||||
raise NotImplementedError("Must be subclassed")
|
||||
|
||||
|
||||
def wheel(pos):
|
||||
"""
|
||||
Helper to create a colorwheel.
|
||||
|
||||
:param pos: int 0-255 of color value to return
|
||||
:return: tuple of RGB values
|
||||
"""
|
||||
# Input a value 0 to 255 to get a color value.
|
||||
# The colours are a transition r - g - b - back to r.
|
||||
if pos < 0 or pos > 255:
|
||||
return 0, 0, 0
|
||||
if pos < 85:
|
||||
return 255 - pos * 3, pos * 3, 0
|
||||
if pos < 170:
|
||||
pos -= 85
|
||||
return 0, 255 - pos * 3, pos * 3
|
||||
pos -= 170
|
||||
return pos * 3, 0, 255 - pos * 3
|
56
ports/esp32s2/boards/unexpectedmaker_pros2/board.c
Normal file
56
ports/esp32s2/boards/unexpectedmaker_pros2/board.c
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "boards/board.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
|
||||
void board_init(void) {
|
||||
// USB
|
||||
common_hal_never_reset_pin(&pin_GPIO19);
|
||||
common_hal_never_reset_pin(&pin_GPIO20);
|
||||
|
||||
// Debug UART
|
||||
common_hal_never_reset_pin(&pin_GPIO43);
|
||||
common_hal_never_reset_pin(&pin_GPIO44);
|
||||
|
||||
// SPI Flash and RAM
|
||||
common_hal_never_reset_pin(&pin_GPIO26);
|
||||
common_hal_never_reset_pin(&pin_GPIO27);
|
||||
common_hal_never_reset_pin(&pin_GPIO28);
|
||||
common_hal_never_reset_pin(&pin_GPIO29);
|
||||
common_hal_never_reset_pin(&pin_GPIO30);
|
||||
common_hal_never_reset_pin(&pin_GPIO31);
|
||||
common_hal_never_reset_pin(&pin_GPIO32);
|
||||
}
|
||||
|
||||
bool board_requests_safe_mode(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void reset_board(void) {
|
||||
|
||||
}
|
35
ports/esp32s2/boards/unexpectedmaker_pros2/mpconfigboard.h
Normal file
35
ports/esp32s2/boards/unexpectedmaker_pros2/mpconfigboard.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
//Micropython setup
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "ProS2"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32S2"
|
||||
|
||||
#define AUTORESET_DELAY_MS 500
|
||||
|
||||
#define MICROPY_HW_APA102_MOSI (&pin_GPIO40)
|
||||
#define MICROPY_HW_APA102_SCK (&pin_GPIO45)
|
21
ports/esp32s2/boards/unexpectedmaker_pros2/mpconfigboard.mk
Normal file
21
ports/esp32s2/boards/unexpectedmaker_pros2/mpconfigboard.mk
Normal file
@ -0,0 +1,21 @@
|
||||
USB_VID = 0x239A
|
||||
USB_PID = 0x80AA
|
||||
USB_PRODUCT = "ProS2"
|
||||
USB_MANUFACTURER = "UnexpectedMaker"
|
||||
USB_DEVICES = "CDC,MSC,HID"
|
||||
|
||||
INTERNAL_FLASH_FILESYSTEM = 1
|
||||
LONGINT_IMPL = MPZ
|
||||
|
||||
# The default queue depth of 16 overflows on release builds,
|
||||
# so increase it to 32.
|
||||
CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
|
||||
|
||||
CIRCUITPY_ESP_FLASH_MODE=qio
|
||||
CIRCUITPY_ESP_FLASH_FREQ=40m
|
||||
CIRCUITPY_ESP_FLASH_SIZE=16MB
|
||||
|
||||
CIRCUITPY_BITBANG_APA102 = 1
|
||||
|
||||
# Include these Python libraries in firmware.
|
||||
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DotStar
|
58
ports/esp32s2/boards/unexpectedmaker_pros2/pins.c
Normal file
58
ports/esp32s2/boards/unexpectedmaker_pros2/pins.c
Normal file
@ -0,0 +1,58 @@
|
||||
#include "shared-bindings/board/__init__.h"
|
||||
|
||||
STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO17) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO18) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO18) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO4) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO4) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO12) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO6) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO6) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO5) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO36) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_GPIO35) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO37) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO44) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO43) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO9) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO3) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO9) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO11) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_GPIO40) }, // MTDO
|
||||
{ MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_GPIO45) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_LDO2), MP_ROM_PTR(&pin_GPIO21) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO14) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
|
||||
};
|
||||
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
|
63
ports/esp32s2/boards/unexpectedmaker_pros2/pros2.py
Normal file
63
ports/esp32s2/boards/unexpectedmaker_pros2/pros2.py
Normal file
@ -0,0 +1,63 @@
|
||||
# Pros2 Helper Library
|
||||
# 2020 Seon Rozenblum, Unexpected Maker
|
||||
#
|
||||
# Project home:
|
||||
# https://pros2.io
|
||||
#
|
||||
|
||||
# Import required libraries
|
||||
import time
|
||||
import board
|
||||
from digitalio import DigitalInOut, Direction, Pull
|
||||
from analogio import AnalogIn
|
||||
|
||||
|
||||
# Helper functions
|
||||
|
||||
def enable_LDO2(state):
|
||||
"""Set the power for the second on-board LDO to allow no current draw when not needed."""
|
||||
|
||||
# Grab a reference to the LDO2 IO (21 in this case)
|
||||
ldo2 = DigitalInOut(board.LDO2)
|
||||
ldo2.direction = Direction.OUTPUT
|
||||
|
||||
# Set the LDO2 power pin on / off
|
||||
ldo2.value = state
|
||||
|
||||
# A small delay to let the IO change state
|
||||
time.sleep(0.035)
|
||||
|
||||
|
||||
# Dotstar rainbow colour wheel
|
||||
def dotstar_color_wheel(wheel_pos):
|
||||
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
|
||||
wheel_pos = wheel_pos % 255
|
||||
|
||||
if wheel_pos < 85:
|
||||
return 255 - wheel_pos * 3, 0, wheel_pos * 3
|
||||
elif wheel_pos < 170:
|
||||
wheel_pos -= 85
|
||||
return 0, wheel_pos * 3, 255 - wheel_pos * 3
|
||||
else:
|
||||
wheel_pos -= 170
|
||||
return wheel_pos * 3, 255 - wheel_pos * 3, 0
|
||||
|
||||
|
||||
# Get a *rough* estimate of the current battery voltage
|
||||
# If the battery is not present, the charge IC will still report it's trying to charge at X voltage
|
||||
# so it will still show a voltage.
|
||||
def get_battery_voltage():
|
||||
"""
|
||||
Returns the current battery voltage. If no battery is connected, returns 3.7V
|
||||
This is an approximation only, but useful to detect of the charge state of the battery is getting low.
|
||||
"""
|
||||
adc = AnalogIn(board.VBAT_SENSE)
|
||||
|
||||
measured_vbat = adc.value # Read the value
|
||||
measured_vbat /= 4095 # divide by 4095 as we are using the default ADC voltage range of 0-1V
|
||||
measured_vbat *= 3.7 # Multiply by 3.7V, our reference voltage
|
||||
return measured_vbat
|
||||
|
||||
|
||||
# Disable LDO2 by default
|
||||
enable_LDO2(False)
|
35
ports/esp32s2/boards/unexpectedmaker_pros2/sdkconfig
Normal file
35
ports/esp32s2/boards/unexpectedmaker_pros2/sdkconfig
Normal file
@ -0,0 +1,35 @@
|
||||
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
|
||||
|
||||
#
|
||||
# SPI RAM config
|
||||
#
|
||||
# CONFIG_SPIRAM_TYPE_AUTO is not set
|
||||
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
|
||||
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
|
||||
CONFIG_SPIRAM_TYPE_ESPPSRAM64=y
|
||||
CONFIG_SPIRAM_SIZE=8388608
|
||||
|
||||
#
|
||||
# PSRAM clock and cs IO for ESP32S2
|
||||
#
|
||||
CONFIG_DEFAULT_PSRAM_CLK_IO=30
|
||||
CONFIG_DEFAULT_PSRAM_CS_IO=26
|
||||
# end of PSRAM clock and cs IO for ESP32S2
|
||||
|
||||
CONFIG_SPIRAM_SPIWP_SD3_PIN=28
|
||||
# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
|
||||
# CONFIG_SPIRAM_RODATA is not set
|
||||
# CONFIG_SPIRAM_USE_AHB_DBUS3 is not set
|
||||
# CONFIG_SPIRAM_SPEED_80M is not set
|
||||
CONFIG_SPIRAM_SPEED_40M=y
|
||||
# CONFIG_SPIRAM_SPEED_26M is not set
|
||||
# CONFIG_SPIRAM_SPEED_20M is not set
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_BOOT_INIT=y
|
||||
# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
|
||||
CONFIG_SPIRAM_USE_MEMMAP=y
|
||||
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
|
||||
# CONFIG_SPIRAM_USE_MALLOC is not set
|
||||
CONFIG_SPIRAM_MEMTEST=y
|
||||
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
|
||||
# end of SPI RAM config
|
Loading…
Reference in New Issue
Block a user