diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..48dffdd
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,9 @@
+.DEFAULT_GOAL := send
+
+.PHONY: send
+send:
+ cp code/code.py /media/chee/prettychips/
+
+.PHONY: init
+init:
+ cp -r code/* /media/chee/prettychips/
diff --git a/code/code.py b/code/code.py
new file mode 100755
index 0000000..14ecb5c
--- /dev/null
+++ b/code/code.py
@@ -0,0 +1,110 @@
+import board
+import time
+import displayio
+import gamepadshift
+import adafruit_imageload
+
+MODE_LIVE = 0
+MODE_MENU1 = 1
+MODE_MENU2 = 2
+
+SOUND_TYPE_SQUARE = 0
+SOUND_TYPE_PULSE = 1
+SOUND_TYPE_SINE = 2
+SOUND_TYPE_NOISE = 3
+
+class PitchEnvelope():
+ pass
+
+class AmpEnvelope():
+ pass
+
+class SoundBlock():
+ index = -1
+ note = None
+ intervals = [0, 0, 0]
+ interval_mode = 0
+ octave = 3
+ pitch_env = PitchEnvelope()
+ amp_env = AmpEnvelope()
+ delay = 0
+ pan = 0
+ def __init__(self, index):
+ self.index = index
+
+class Sound():
+ name = None
+ type = None
+ blocks = []
+ rate = 8 # 8 for normal, 4 for half, 2 for quarter, 1 for eigth
+
+ def __init__(self, machine, name, type):
+ self.machine = machine
+ self.name = name
+ self.type = type
+ for i in range(16):
+ self.blocks.append(SoundBlock(i))
+ @property
+ def playing_block(self):
+ return self.machine.current_tick // self.rate
+
+class BleepBloopMachine():
+ mode = MODE_LIVE
+ bpm = 120
+ current_tick = 0
+ max_tick = 127
+ selected_live_block = 0
+ selected_menu1_control = 0
+ selected_menu2_control = 0
+ current_sound_index = 0
+ sounds = []
+ @property
+ def tick_length(self):
+ return self.bpm / self.max_tick / 16
+ @property
+ def current_sound(self):
+ return self.sounds[self.current_sound_index]
+ def tick(self):
+ time.sleep(self.tick_length)
+ self.current_tick += 1
+ if self.current_tick > 127:
+ self.current_tick = 0
+ def __init__(self):
+ self.sounds.append(Sound(self, "q", SOUND_TYPE_SQUARE))
+ self.sounds.append(Sound(self, "p", SOUND_TYPE_PULSE))
+ self.sounds.append(Sound(self, "s", SOUND_TYPE_SINE))
+ self.sounds.append(Sound(self, "n", SOUND_TYPE_NOISE))
+
+machine = BleepBloopMachine()
+
+display = board.DISPLAY
+
+colorsheet, palette = adafruit_imageload.load(
+ "colors.bmp",
+ bitmap=displayio.Bitmap,
+ palette=displayio.Palette,
+)
+grid = displayio.TileGrid(
+ colorsheet,
+ pixel_shader=palette,
+ width=10,
+ height=8,
+ tile_width=16,
+ tile_height=16,
+)
+grid_group = displayio.Group()
+grid_group.append(grid)
+display.show(grid_group)
+
+sound = machine.current_sound
+while True:
+ sound = machine.current_sound
+ for y in range(0, 4):
+ for x in range(0, 4):
+ color = 1
+ if x == sound.playing_block % 4 and y == sound.playing_block // 4:
+ color = 2
+ grid[x + 3, y + 2] = color
+ print(sound.playing_block)
+ print(x, y, sound.playing_block / 4)
+ machine.tick()
diff --git a/code/colors.bmp b/code/colors.bmp
new file mode 100644
index 0000000..fefe5de
Binary files /dev/null and b/code/colors.bmp differ
diff --git a/code/lib/adafruit_imageload/__init__.mpy b/code/lib/adafruit_imageload/__init__.mpy
new file mode 100644
index 0000000..0e4341b
Binary files /dev/null and b/code/lib/adafruit_imageload/__init__.mpy differ
diff --git a/code/lib/adafruit_imageload/bmp/__init__.mpy b/code/lib/adafruit_imageload/bmp/__init__.mpy
new file mode 100644
index 0000000..f610ba1
Binary files /dev/null and b/code/lib/adafruit_imageload/bmp/__init__.mpy differ
diff --git a/code/lib/adafruit_imageload/bmp/indexed.mpy b/code/lib/adafruit_imageload/bmp/indexed.mpy
new file mode 100644
index 0000000..b375035
Binary files /dev/null and b/code/lib/adafruit_imageload/bmp/indexed.mpy differ
diff --git a/code/lib/adafruit_imageload/bmp/negative_height_check.mpy b/code/lib/adafruit_imageload/bmp/negative_height_check.mpy
new file mode 100644
index 0000000..a0c86e4
Binary files /dev/null and b/code/lib/adafruit_imageload/bmp/negative_height_check.mpy differ
diff --git a/code/lib/adafruit_imageload/gif.mpy b/code/lib/adafruit_imageload/gif.mpy
new file mode 100644
index 0000000..6c3c982
Binary files /dev/null and b/code/lib/adafruit_imageload/gif.mpy differ
diff --git a/code/lib/adafruit_imageload/pnm/__init__.mpy b/code/lib/adafruit_imageload/pnm/__init__.mpy
new file mode 100644
index 0000000..73d3de1
Binary files /dev/null and b/code/lib/adafruit_imageload/pnm/__init__.mpy differ
diff --git a/code/lib/adafruit_imageload/pnm/pbm_ascii.mpy b/code/lib/adafruit_imageload/pnm/pbm_ascii.mpy
new file mode 100644
index 0000000..53970a8
Binary files /dev/null and b/code/lib/adafruit_imageload/pnm/pbm_ascii.mpy differ
diff --git a/code/lib/adafruit_imageload/pnm/pbm_binary.mpy b/code/lib/adafruit_imageload/pnm/pbm_binary.mpy
new file mode 100644
index 0000000..dcdde64
Binary files /dev/null and b/code/lib/adafruit_imageload/pnm/pbm_binary.mpy differ
diff --git a/code/lib/adafruit_imageload/pnm/pgm/__init__.mpy b/code/lib/adafruit_imageload/pnm/pgm/__init__.mpy
new file mode 100644
index 0000000..efcb83d
Binary files /dev/null and b/code/lib/adafruit_imageload/pnm/pgm/__init__.mpy differ
diff --git a/code/lib/adafruit_imageload/pnm/pgm/ascii.mpy b/code/lib/adafruit_imageload/pnm/pgm/ascii.mpy
new file mode 100644
index 0000000..26bac4f
Binary files /dev/null and b/code/lib/adafruit_imageload/pnm/pgm/ascii.mpy differ
diff --git a/code/lib/adafruit_imageload/pnm/pgm/binary.mpy b/code/lib/adafruit_imageload/pnm/pgm/binary.mpy
new file mode 100644
index 0000000..7da0e3d
Binary files /dev/null and b/code/lib/adafruit_imageload/pnm/pgm/binary.mpy differ
diff --git a/code/lib/adafruit_imageload/pnm/ppm_ascii.mpy b/code/lib/adafruit_imageload/pnm/ppm_ascii.mpy
new file mode 100644
index 0000000..7fef95a
Binary files /dev/null and b/code/lib/adafruit_imageload/pnm/ppm_ascii.mpy differ
diff --git a/code/lib/adafruit_imageload/pnm/ppm_binary.mpy b/code/lib/adafruit_imageload/pnm/ppm_binary.mpy
new file mode 100644
index 0000000..ae97974
Binary files /dev/null and b/code/lib/adafruit_imageload/pnm/ppm_binary.mpy differ
diff --git a/pyrightconfig.json b/pyrightconfig.json
new file mode 100644
index 0000000..161d791
--- /dev/null
+++ b/pyrightconfig.json
@@ -0,0 +1,4 @@
+{
+ "stubPath": "./stubs",
+ "include": ["./code/*", "./code/lib/*"]
+}
diff --git a/stubs/_bleio/__init__.pyi b/stubs/_bleio/__init__.pyi
new file mode 100644
index 0000000..d9397c0
--- /dev/null
+++ b/stubs/_bleio/__init__.pyi
@@ -0,0 +1,686 @@
+"""Bluetooth Low Energy (BLE) communication
+
+The `_bleio` module provides necessary low-level functionality for communicating
+using Bluetooth Low Energy (BLE). The '_' prefix indicates this module is meant
+for internal use by libraries but not by the end user. Its API may change incompatibly
+between minor versions of CircuitPython.
+Please use the
+`adafruit_ble `_
+CircuitPython library instead, which builds on `_bleio`, and
+provides higher-level convenience functionality, including predefined beacons, clients,
+servers."""
+
+from __future__ import annotations
+
+from typing import Iterable, Iterator, Optional, Tuple, Union
+
+import _bleio
+import busio
+import digitalio
+from _typing import ReadableBuffer, WriteableBuffer
+
+adapter: Adapter
+"""BLE Adapter used to manage device discovery and connections.
+This object is the sole instance of `_bleio.Adapter`."""
+
+class BluetoothError(Exception):
+ """Catchall exception for Bluetooth related errors."""
+
+ ...
+
+class RoleError(BluetoothError):
+ """Raised when a resource is used as the mismatched role. For example, if a local CCCD is
+ attempted to be set but they can only be set when remote."""
+
+ ...
+
+class SecurityError(BluetoothError):
+ """Raised when a security related error occurs."""
+
+ ...
+
+def set_adapter(adapter: Optional[_bleio.Adapter]) -> None:
+ """Set the adapter to use for BLE, such as when using an HCI adapter.
+ Raises `NotImplementedError` when the adapter is a singleton and cannot be set."""
+ ...
+
+class Adapter:
+ """
+ The BLE Adapter object manages the discovery and connection to other nearby Bluetooth Low Energy devices.
+ This part of the Bluetooth Low Energy Specification is known as Generic Access Profile (GAP).
+
+ Discovery of other devices happens during a scanning process that listens for small packets of
+ information, known as advertisements, that are broadcast unencrypted. The advertising packets
+ have two different uses. The first is to broadcast a small piece of data to anyone who cares and
+ and nothing more. These are known as beacons. The second class of advertisement is to promote
+ additional functionality available after the devices establish a connection. For example, a
+ BLE heart rate monitor would advertise that it provides the standard BLE Heart Rate Service.
+
+ The Adapter can do both parts of this process: it can scan for other device
+ advertisements and it can advertise its own data. Furthermore, Adapters can accept incoming
+ connections and also initiate connections."""
+
+ def __init__(
+ self,
+ *,
+ uart: busio.UART,
+ rts: digitalio.DigitalInOut,
+ cts: digitalio.DigitalInOut
+ ) -> None:
+ """On boards that do not have native BLE, you can use an HCI co-processor.
+ Pass the uart and pins used to communicate with the co-processor, such as an Adafruit AirLift.
+ The co-processor must have been reset and put into BLE mode beforehand
+ by the appropriate pin manipulation.
+ The ``uart``, ``rts``, and ``cts`` objects are used to
+ communicate with the HCI co-processor in HCI mode.
+ The `Adapter` object is enabled during this call.
+
+ After instantiating an Adapter, call `_bleio.set_adapter()` to set `_bleio.adapter`
+
+ On boards with native BLE, you cannot create an instance of `_bleio.Adapter`;
+ this constructor will raise `NotImplementedError`.
+ Use `_bleio.adapter` to access the sole instance already available.
+ """
+ ...
+ enabled: bool
+ """State of the BLE adapter."""
+
+ address: Address
+ """MAC address of the BLE adapter."""
+
+ name: str
+ """name of the BLE adapter used once connected.
+ The name is "CIRCUITPY" + the last four hex digits of ``adapter.address``,
+ to make it easy to distinguish multiple CircuitPython boards."""
+ def start_advertising(
+ self,
+ data: ReadableBuffer,
+ *,
+ scan_response: Optional[ReadableBuffer] = None,
+ connectable: bool = True,
+ anonymous: bool = False,
+ timeout: int = 0,
+ interval: float = 0.1
+ ) -> None:
+ """Starts advertising until `stop_advertising` is called or if connectable, another device
+ connects to us.
+
+ .. warning: If data is longer than 31 bytes, then this will automatically advertise as an
+ extended advertisement that older BLE 4.x clients won't be able to scan for.
+
+ .. note: If you set ``anonymous=True``, then a timeout must be specified. If no timeout is
+ specified, then the maximum allowed timeout will be selected automatically.
+
+ :param ~_typing.ReadableBuffer data: advertising data packet bytes
+ :param ~_typing.ReadableBuffer scan_response: scan response data packet bytes. ``None`` if no scan response is needed.
+ :param bool connectable: If `True` then other devices are allowed to connect to this peripheral.
+ :param bool anonymous: If `True` then this device's MAC address is randomized before advertising.
+ :param int timeout: If set, we will only advertise for this many seconds.
+ :param float interval: advertising interval, in seconds"""
+ ...
+ def stop_advertising(self) -> None:
+ """Stop sending advertising packets."""
+ ...
+ def start_scan(
+ self,
+ prefixes: ReadableBuffer = b"",
+ *,
+ buffer_size: int = 512,
+ extended: bool = False,
+ timeout: Optional[float] = None,
+ interval: float = 0.1,
+ window: float = 0.1,
+ minimum_rssi: int = -80,
+ active: bool = True
+ ) -> Iterable[ScanEntry]:
+ """Starts a BLE scan and returns an iterator of results. Advertisements and scan responses are
+ filtered and returned separately.
+
+ :param ~_typing.ReadableBuffer prefixes: Sequence of byte string prefixes to filter advertising packets
+ with. A packet without an advertising structure that matches one of the prefixes is
+ ignored. Format is one byte for length (n) and n bytes of prefix and can be repeated.
+ :param int buffer_size: the maximum number of advertising bytes to buffer.
+ :param bool extended: When True, support extended advertising packets. Increasing buffer_size is recommended when this is set.
+ :param float timeout: the scan timeout in seconds. If None, will scan until `stop_scan` is called.
+ :param float interval: the interval (in seconds) between the start of two consecutive scan windows
+ Must be in the range 0.0025 - 40.959375 seconds.
+ :param float window: the duration (in seconds) to scan a single BLE channel.
+ window must be <= interval.
+ :param int minimum_rssi: the minimum rssi of entries to return.
+ :param bool active: retrieve scan responses for scannable advertisements.
+ :returns: an iterable of `_bleio.ScanEntry` objects
+ :rtype: iterable"""
+ ...
+ def stop_scan(self) -> None:
+ """Stop the current scan."""
+ ...
+ advertising: bool
+ """True when the adapter is currently advertising. (read-only)"""
+
+ connected: bool
+ """True when the adapter is connected to another device regardless of who initiated the
+ connection. (read-only)"""
+
+ connections: Tuple[Connection]
+ """Tuple of active connections including those initiated through
+ :py:meth:`_bleio.Adapter.connect`. (read-only)"""
+ def connect(self, address: Address, *, timeout: float) -> Connection:
+ """Attempts a connection to the device with the given address.
+
+ :param Address address: The address of the peripheral to connect to
+ :param float/int timeout: Try to connect for timeout seconds."""
+ ...
+ def erase_bonding(self) -> None:
+ """Erase all bonding information stored in flash memory."""
+ ...
+
+class Address:
+ """Encapsulates the address of a BLE device."""
+
+ def __init__(self, address: ReadableBuffer, address_type: int) -> None:
+ """Create a new Address object encapsulating the address value.
+ The value itself can be one of:
+
+ :param ~_typing.ReadableBuffer address: The address value to encapsulate. A buffer object (bytearray, bytes) of 6 bytes.
+ :param int address_type: one of the integer values: `PUBLIC`, `RANDOM_STATIC`,
+ `RANDOM_PRIVATE_RESOLVABLE`, or `RANDOM_PRIVATE_NON_RESOLVABLE`."""
+ ...
+ address_bytes: bytes
+ """The bytes that make up the device address (read-only).
+
+ Note that the ``bytes`` object returned is in little-endian order:
+ The least significant byte is ``address_bytes[0]``. So the address will
+ appear to be reversed if you print the raw ``bytes`` object. If you print
+ or use `str()` on the :py:class:`~_bleio.Attribute` object itself, the address will be printed
+ in the expected order. For example:
+
+ .. code-block:: python
+
+ >>> import _bleio
+ >>> _bleio.adapter.address
+
+ >>> _bleio.adapter.address.address_bytes
+ b'5\\xa8\\xed\\xf5\\x1d\\xc8'"""
+
+ type: int
+ """The address type (read-only).
+
+ One of the integer values: `PUBLIC`, `RANDOM_STATIC`, `RANDOM_PRIVATE_RESOLVABLE`,
+ or `RANDOM_PRIVATE_NON_RESOLVABLE`."""
+ def __eq__(self, other: object) -> bool:
+ """Two Address objects are equal if their addresses and address types are equal."""
+ ...
+ def __hash__(self) -> int:
+ """Returns a hash for the Address data."""
+ ...
+ PUBLIC: int
+ """A publicly known address, with a company ID (high 24 bits)and company-assigned part (low 24 bits)."""
+
+ RANDOM_STATIC: int
+ """A randomly generated address that does not change often. It may never change or may change after
+ a power cycle."""
+
+ RANDOM_PRIVATE_RESOLVABLE: int
+ """An address that is usable when the peer knows the other device's secret Identity Resolving Key (IRK)."""
+
+ RANDOM_PRIVATE_NON_RESOLVABLE: int
+ """A randomly generated address that changes on every connection."""
+
+class Attribute:
+ """Definitions associated with all BLE attributes: characteristics, descriptors, etc.
+
+ :py:class:`~_bleio.Attribute` is, notionally, a superclass of
+ :py:class:`~Characteristic` and :py:class:`~Descriptor`,
+ but is not defined as a Python superclass of those classes."""
+
+ def __init__(self) -> None:
+ """You cannot create an instance of :py:class:`~_bleio.Attribute`."""
+ ...
+ NO_ACCESS: int
+ """security mode: access not allowed"""
+
+ OPEN: int
+ """security_mode: no security (link is not encrypted)"""
+
+ ENCRYPT_NO_MITM: int
+ """security_mode: unauthenticated encryption, without man-in-the-middle protection"""
+
+ ENCRYPT_WITH_MITM: int
+ """security_mode: authenticated encryption, with man-in-the-middle protection"""
+
+ LESC_ENCRYPT_WITH_MITM: int
+ """security_mode: LESC encryption, with man-in-the-middle protection"""
+
+ SIGNED_NO_MITM: int
+ """security_mode: unauthenticated data signing, without man-in-the-middle protection"""
+
+ SIGNED_WITH_MITM: int
+ """security_mode: authenticated data signing, without man-in-the-middle protection"""
+
+class Characteristic:
+ """Stores information about a BLE service characteristic and allows reading
+ and writing of the characteristic's value."""
+
+ def __init__(self) -> None:
+ """There is no regular constructor for a Characteristic. A new local Characteristic can be created
+ and attached to a Service by calling `add_to_service()`.
+ Remote Characteristic objects are created by `Connection.discover_remote_services()`
+ as part of remote Services."""
+ ...
+ def add_to_service(
+ self,
+ service: Service,
+ uuid: UUID,
+ *,
+ properties: int = 0,
+ read_perm: int = Attribute.OPEN,
+ write_perm: int = Attribute.OPEN,
+ max_length: int = 20,
+ fixed_length: bool = False,
+ initial_value: Optional[ReadableBuffer] = None
+ ) -> Characteristic:
+ """Create a new Characteristic object, and add it to this Service.
+
+ :param Service service: The service that will provide this characteristic
+ :param UUID uuid: The uuid of the characteristic
+ :param int properties: The properties of the characteristic,
+ specified as a bitmask of these values bitwise-or'd together:
+ `BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`.
+ :param int read_perm: Specifies whether the characteristic can be read by a client, and if so, which
+ security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`,
+ `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`,
+ `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`.
+ :param int write_perm: Specifies whether the characteristic can be written by a client, and if so, which
+ security mode is required. Values allowed are the same as ``read_perm``.
+ :param int max_length: Maximum length in bytes of the characteristic value. The maximum allowed is
+ is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum
+ number of data bytes that fit in a single BLE 4.x ATT packet.
+ :param bool fixed_length: True if the characteristic value is of fixed length.
+ :param ~_typing.ReadableBuffer initial_value: The initial value for this characteristic. If not given, will be
+ filled with zeros.
+
+ :return: the new Characteristic."""
+ ...
+ properties: int
+ """An int bitmask representing which properties are set, specified as bitwise or'ing of
+ of these possible values.
+ `BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`."""
+
+ uuid: Optional[UUID]
+ """The UUID of this characteristic. (read-only)
+
+ Will be ``None`` if the 128-bit UUID for this characteristic is not known."""
+
+ value: bytearray
+ """The value of this characteristic."""
+
+ descriptors: Descriptor
+ """A tuple of :py:class:`Descriptor` objects related to this characteristic. (read-only)"""
+
+ service: Service
+ """The Service this Characteristic is a part of."""
+ def set_cccd(self, *, notify: bool = False, indicate: bool = False) -> None:
+ """Set the remote characteristic's CCCD to enable or disable notification and indication.
+
+ :param bool notify: True if Characteristic should receive notifications of remote writes
+ :param float indicate: True if Characteristic should receive indications of remote writes"""
+ ...
+ BROADCAST: int
+ """property: allowed in advertising packets"""
+
+ INDICATE: int
+ """property: server will indicate to the client when the value is set and wait for a response"""
+
+ NOTIFY: int
+ """property: server will notify the client when the value is set"""
+
+ READ: int
+ """property: clients may read this characteristic"""
+
+ WRITE: int
+ """property: clients may write this characteristic; a response will be sent back"""
+
+ WRITE_NO_RESPONSE: int
+ """property: clients may write this characteristic; no response will be sent back"""
+
+class CharacteristicBuffer:
+ """Accumulates a Characteristic's incoming values in a FIFO buffer."""
+
+ def __init__(
+ self, characteristic: Characteristic, *, timeout: int = 1, buffer_size: int = 64
+ ) -> None:
+
+ """Monitor the given Characteristic. Each time a new value is written to the Characteristic
+ add the newly-written bytes to a FIFO buffer.
+
+ :param Characteristic characteristic: The Characteristic to monitor.
+ It may be a local Characteristic provided by a Peripheral Service, or a remote Characteristic
+ in a remote Service that a Central has connected to.
+ :param int timeout: the timeout in seconds to wait for the first character and between subsequent characters.
+ :param int buffer_size: Size of ring buffer that stores incoming data coming from client.
+ Must be >= 1."""
+ ...
+ def read(self, nbytes: Optional[int] = None) -> Optional[bytes]:
+ """Read characters. If ``nbytes`` is specified then read at most that many
+ bytes. Otherwise, read everything that arrives until the connection
+ times out. Providing the number of bytes expected is highly recommended
+ because it will be faster.
+
+ :return: Data read
+ :rtype: bytes or None"""
+ ...
+ def readinto(self, buf: WriteableBuffer) -> Optional[int]:
+ """Read bytes into the ``buf``. Read at most ``len(buf)`` bytes.
+
+ :return: number of bytes read and stored into ``buf``
+ :rtype: int or None (on a non-blocking error)"""
+ ...
+ def readline(self) -> bytes:
+ """Read a line, ending in a newline character.
+
+ :return: the line read
+ :rtype: int or None"""
+ ...
+ in_waiting: int
+ """The number of bytes in the input buffer, available to be read"""
+ def reset_input_buffer(self) -> None:
+ """Discard any unread characters in the input buffer."""
+ ...
+ def deinit(self) -> None:
+ """Disable permanently."""
+ ...
+
+class Connection:
+ """A BLE connection to another device. Used to discover and interact with services on the other
+ device.
+
+ Usage::
+
+ import _bleio
+
+ my_entry = None
+ for entry in _bleio.adapter.scan(2.5):
+ if entry.name is not None and entry.name == 'InterestingPeripheral':
+ my_entry = entry
+ break
+
+ if not my_entry:
+ raise Exception("'InterestingPeripheral' not found")
+
+ connection = _bleio.adapter.connect(my_entry.address, timeout=10)"""
+
+ def __init__(self) -> None:
+ """Connections cannot be made directly. Instead, to initiate a connection use `Adapter.connect`.
+ Connections may also be made when another device initiates a connection. To use a Connection
+ created by a peer, read the `Adapter.connections` property."""
+ ...
+ def disconnect(self) -> None:
+ """Disconnects from the remote peripheral. Does nothing if already disconnected."""
+ ...
+ def pair(self, *, bond: bool = True) -> None:
+ """Pair to the peer to improve security."""
+ ...
+ def discover_remote_services(
+ self, service_uuids_whitelist: Optional[Iterable[UUID]] = None
+ ) -> Tuple[Service, ...]:
+ """Do BLE discovery for all services or for the given service UUIDS,
+ to find their handles and characteristics, and return the discovered services.
+ `Connection.connected` must be True.
+
+ :param iterable service_uuids_whitelist:
+
+ an iterable of :py:class:`UUID` objects for the services provided by the peripheral
+ that you want to use.
+
+ The peripheral may provide more services, but services not listed are ignored
+ and will not be returned.
+
+ If service_uuids_whitelist is None, then all services will undergo discovery, which can be
+ slow.
+
+ If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you
+ you must have already created a :py:class:`UUID` object for that UUID in order for the
+ service or characteristic to be discovered. Creating the UUID causes the UUID to be
+ registered for use. (This restriction may be lifted in the future.)
+
+ :return: A tuple of `_bleio.Service` objects provided by the remote peripheral."""
+ ...
+ connected: bool
+ """True if connected to the remote peer."""
+
+ paired: bool
+ """True if paired to the remote peer."""
+
+ connection_interval: float
+ """Time between transmissions in milliseconds. Will be multiple of 1.25ms. Lower numbers
+ increase speed and decrease latency but increase power consumption.
+
+ When setting connection_interval, the peer may reject the new interval and
+ `connection_interval` will then remain the same.
+
+ Apple has additional guidelines that dictate should be a multiple of 15ms except if HID is
+ available. When HID is available Apple devices may accept 11.25ms intervals."""
+
+ attribute: int
+ """The maximum number of data bytes that can be sent in a single transmission,
+ not including overhead bytes.
+
+ This is the maximum number of bytes that can be sent in a notification,
+ which must be sent in a single packet.
+ But for a regular characteristic read or write, may be sent in multiple packets,
+ so this limit does not apply."""
+
+class Descriptor:
+ """Stores information about a BLE descriptor.
+
+ Descriptors are attached to BLE characteristics and provide contextual
+ information about the characteristic."""
+
+ def __init__(self) -> None:
+ """There is no regular constructor for a Descriptor. A new local Descriptor can be created
+ and attached to a Characteristic by calling `add_to_characteristic()`.
+ Remote Descriptor objects are created by `Connection.discover_remote_services()`
+ as part of remote Characteristics in the remote Services that are discovered."""
+ @classmethod
+ def add_to_characteristic(
+ cls,
+ characteristic: Characteristic,
+ uuid: UUID,
+ *,
+ read_perm: int = Attribute.OPEN,
+ write_perm: int = Attribute.OPEN,
+ max_length: int = 20,
+ fixed_length: bool = False,
+ initial_value: ReadableBuffer = b""
+ ) -> Descriptor:
+ """Create a new Descriptor object, and add it to this Service.
+
+ :param Characteristic characteristic: The characteristic that will hold this descriptor
+ :param UUID uuid: The uuid of the descriptor
+ :param int read_perm: Specifies whether the descriptor can be read by a client, and if so, which
+ security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`,
+ `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`,
+ `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`.
+ :param int write_perm: Specifies whether the descriptor can be written by a client, and if so, which
+ security mode is required. Values allowed are the same as ``read_perm``.
+ :param int max_length: Maximum length in bytes of the descriptor value. The maximum allowed is
+ is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum
+ number of data bytes that fit in a single BLE 4.x ATT packet.
+ :param bool fixed_length: True if the descriptor value is of fixed length.
+ :param ~_typing.ReadableBuffer initial_value: The initial value for this descriptor.
+
+ :return: the new Descriptor."""
+ ...
+ uuid: UUID
+ """The descriptor uuid. (read-only)"""
+
+ characteristic: Characteristic
+ """The Characteristic this Descriptor is a part of."""
+
+ value: bytearray
+ """The value of this descriptor."""
+
+class PacketBuffer:
+ """Accumulates a Characteristic's incoming packets in a FIFO buffer and facilitates packet aware
+ outgoing writes. A packet's size is either the characteristic length or the maximum transmission
+ unit (MTU) minus overhead, whichever is smaller. The MTU can change so check `incoming_packet_length`
+ and `outgoing_packet_length` before creating a buffer to store data.
+
+ When we're the server, we ignore all connections besides the first to subscribe to
+ notifications."""
+
+ def __init__(self, characteristic: Characteristic, *, buffer_size: int) -> None:
+ """Monitor the given Characteristic. Each time a new value is written to the Characteristic
+ add the newly-written bytes to a FIFO buffer.
+
+ Monitor the given Characteristic. Each time a new value is written to the Characteristic
+ add the newly-written packet of bytes to a FIFO buffer.
+
+ :param Characteristic characteristic: The Characteristic to monitor.
+ It may be a local Characteristic provided by a Peripheral Service, or a remote Characteristic
+ in a remote Service that a Central has connected to.
+ :param int buffer_size: Size of ring buffer (in packets of the Characteristic's maximum
+ length) that stores incoming packets coming from the peer."""
+ ...
+ def readinto(self, buf: WriteableBuffer) -> int:
+ """Reads a single BLE packet into the ``buf``. Raises an exception if the next packet is longer
+ than the given buffer. Use `packet_size` to read the maximum length of a single packet.
+
+ :return: number of bytes read and stored into ``buf``
+ :rtype: int"""
+ ...
+ def write(self, data: ReadableBuffer, *, header: Optional[bytes] = None) -> int:
+ """Writes all bytes from data into the same outgoing packet. The bytes from header are included
+ before data when the pending packet is currently empty.
+
+ This does not block until the data is sent. It only blocks until the data is pending.
+
+ :return: number of bytes written. May include header bytes when packet is empty.
+ :rtype: int"""
+ ...
+ def deinit(self) -> None:
+ """Disable permanently."""
+ ...
+ packet_size: int
+ """`packet_size` is the same as `incoming_packet_length`.
+ The name `packet_size` is deprecated and
+ will be removed in CircuitPython 6.0.0."""
+
+ incoming_packet_length: int
+ """Maximum length in bytes of a packet we are reading."""
+
+ outgoing_packet_length: int
+ """Maximum length in bytes of a packet we are writing."""
+
+class ScanEntry:
+ """Encapsulates information about a device that was received during scanning. It can be
+ advertisement or scan response data. This object may only be created by a `_bleio.ScanResults`:
+ it has no user-visible constructor."""
+
+ def __init__(self) -> None:
+ """Cannot be instantiated directly. Use `_bleio.Adapter.start_scan`."""
+ ...
+ def matches(self, prefixes: ScanEntry, *, all: bool = True) -> bool:
+ """Returns True if the ScanEntry matches all prefixes when ``all`` is True. This is stricter
+ than the scan filtering which accepts any advertisements that match any of the prefixes
+ where all is False."""
+ ...
+ address: Address
+ """The address of the device (read-only), of type `_bleio.Address`."""
+
+ advertisement_bytes: bytes
+ """All the advertisement data present in the packet, returned as a ``bytes`` object. (read-only)"""
+
+ rssi: int
+ """The signal strength of the device at the time of the scan, in integer dBm. (read-only)"""
+
+ connectable: bool
+ """True if the device can be connected to. (read-only)"""
+
+ scan_response: bool
+ """True if the entry was a scan response. (read-only)"""
+
+class ScanResults:
+ """Iterates over advertising data received while scanning. This object is always created
+ by a `_bleio.Adapter`: it has no user-visible constructor."""
+
+ def __init__(self) -> None:
+ """Cannot be instantiated directly. Use `_bleio.Adapter.start_scan`."""
+ ...
+ def __iter__(self) -> Iterator[ScanEntry]:
+ """Returns itself since it is the iterator."""
+ ...
+ def __next__(self) -> ScanEntry:
+ """Returns the next `_bleio.ScanEntry`. Blocks if none have been received and scanning is still
+ active. Raises `StopIteration` if scanning is finished and no other results are available."""
+ ...
+
+class Service:
+ """Stores information about a BLE service and its characteristics."""
+
+ def __init__(self, uuid: UUID, *, secondary: bool = False) -> None:
+ """Create a new Service identified by the specified UUID. It can be accessed by all
+ connections. This is known as a Service server. Client Service objects are created via
+ `Connection.discover_remote_services`.
+
+ To mark the Service as secondary, pass `True` as :py:data:`secondary`.
+
+ :param UUID uuid: The uuid of the service
+ :param bool secondary: If the service is a secondary one
+
+ :return: the new Service"""
+ ...
+ characteristics: Tuple[Characteristic, ...]
+ """A tuple of :py:class:`Characteristic` designating the characteristics that are offered by
+ this service. (read-only)"""
+
+ remote: bool
+ """True if this is a service provided by a remote device. (read-only)"""
+
+ secondary: bool
+ """True if this is a secondary service. (read-only)"""
+
+ uuid: Optional[UUID]
+ """The UUID of this service. (read-only)
+
+ Will be ``None`` if the 128-bit UUID for this service is not known."""
+
+class UUID:
+ """A 16-bit or 128-bit UUID. Can be used for services, characteristics, descriptors and more."""
+
+ def __init__(self, value: Union[int, ReadableBuffer, str]) -> None:
+ """Create a new UUID or UUID object encapsulating the uuid value.
+ The value can be one of:
+
+ - an `int` value in range 0 to 0xFFFF (Bluetooth SIG 16-bit UUID)
+ - a buffer object (bytearray, bytes) of 16 bytes in little-endian order (128-bit UUID)
+ - a string of hex digits of the form 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
+
+ Creating a 128-bit UUID registers the UUID with the onboard BLE software, and provides a
+ temporary 16-bit UUID that can be used in place of the full 128-bit UUID.
+
+ :param value: The uuid value to encapsulate
+ :type value: int, ~_typing.ReadableBuffer or str"""
+ ...
+ uuid16: int
+ """The 16-bit part of the UUID. (read-only)
+
+ :type: int"""
+
+ uuid128: bytes
+ """The 128-bit value of the UUID
+ Raises AttributeError if this is a 16-bit UUID. (read-only)
+
+ :type: bytes"""
+
+ size: int
+ """128 if this UUID represents a 128-bit vendor-specific UUID. 16 if this UUID represents a
+ 16-bit Bluetooth SIG assigned UUID. (read-only) 32-bit UUIDs are not currently supported.
+
+ :type: int"""
+ def pack_into(self, buffer: WriteableBuffer, offset: int = 0) -> None:
+ """Packs the UUID into the given buffer at the given offset."""
+ ...
+ def __eq__(self, other: object) -> bool:
+ """Two UUID objects are equal if their values match and they are both 128-bit or both 16-bit."""
+ ...
diff --git a/stubs/_eve/__init__.pyi b/stubs/_eve/__init__.pyi
new file mode 100644
index 0000000..a083ea1
--- /dev/null
+++ b/stubs/_eve/__init__.pyi
@@ -0,0 +1,391 @@
+"""Low-level BridgeTek EVE bindings
+
+The `_eve` module provides a class _EVE which
+contains methods for constructing EVE command
+buffers and appending basic graphics commands."""
+
+from __future__ import annotations
+
+from typing import Tuple
+
+from _typing import ReadableBuffer
+
+class _EVE:
+ def register(self, o: object) -> None: ...
+ def flush(self) -> None:
+ """Send any queued drawing commands directly to the hardware.
+
+ :param int width: The width of the grid in tiles, or 1 for sprites."""
+ ...
+ def cc(self, b: ReadableBuffer) -> None:
+ """Append bytes to the command FIFO.
+
+ :param ~_typing.ReadableBuffer b: The bytes to add"""
+ ...
+ def AlphaFunc(self, func: int, ref: int) -> None:
+ """Set the alpha test function
+
+ :param int func: specifies the test function, one of ``NEVER``, ``LESS``, ``LEQUAL``, ``GREATER``, ``GEQUAL``, ``EQUAL``, ``NOTEQUAL``, or ``ALWAYS``. Range 0-7. The initial value is ALWAYS(7)
+ :param int ref: specifies the reference value for the alpha test. Range 0-255. The initial value is 0
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def Begin(self, prim: int) -> None:
+ """Begin drawing a graphics primitive
+
+ :param int prim: graphics primitive.
+
+ Valid primitives are ``BITMAPS``, ``POINTS``, ``LINES``, ``LINE_STRIP``, ``EDGE_STRIP_R``, ``EDGE_STRIP_L``, ``EDGE_STRIP_A``, ``EDGE_STRIP_B`` and ``RECTS``."""
+ ...
+ def BitmapExtFormat(self, format: int) -> None:
+ """Set the bitmap format
+
+ :param int format: bitmap pixel format."""
+ ...
+ def BitmapHandle(self, handle: int) -> None:
+ """Set the bitmap handle
+
+ :param int handle: bitmap handle. Range 0-31. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def BitmapLayoutH(self, linestride: int, height: int) -> None:
+ """Set the source bitmap memory format and layout for the current handle. high bits for large bitmaps
+
+ :param int linestride: high part of bitmap line stride, in bytes. Range 0-7
+ :param int height: high part of bitmap height, in lines. Range 0-3"""
+ ...
+ def BitmapLayout(self, format: int, linestride: int, height: int) -> None:
+ """Set the source bitmap memory format and layout for the current handle
+
+ :param int format: bitmap pixel format, or GLFORMAT to use BITMAP_EXT_FORMAT instead. Range 0-31
+ :param int linestride: bitmap line stride, in bytes. Range 0-1023
+ :param int height: bitmap height, in lines. Range 0-511"""
+ ...
+ def BitmapSizeH(self, width: int, height: int) -> None:
+ """Set the screen drawing of bitmaps for the current handle. high bits for large bitmaps
+
+ :param int width: high part of drawn bitmap width, in pixels. Range 0-3
+ :param int height: high part of drawn bitmap height, in pixels. Range 0-3"""
+ ...
+ def BitmapSize(
+ self, filter: int, wrapx: int, wrapy: int, width: int, height: int
+ ) -> None:
+ """Set the screen drawing of bitmaps for the current handle
+
+ :param int filter: bitmap filtering mode, one of ``NEAREST`` or ``BILINEAR``. Range 0-1
+ :param int wrapx: bitmap :math:`x` wrap mode, one of ``REPEAT`` or ``BORDER``. Range 0-1
+ :param int wrapy: bitmap :math:`y` wrap mode, one of ``REPEAT`` or ``BORDER``. Range 0-1
+ :param int width: drawn bitmap width, in pixels. Range 0-511
+ :param int height: drawn bitmap height, in pixels. Range 0-511"""
+ ...
+ def BitmapSource(self, addr: int) -> None:
+ """Set the source address for bitmap graphics
+
+ :param int addr: Bitmap start address, pixel-aligned. May be in SRAM or flash. Range 0-16777215"""
+ ...
+ def BitmapSwizzle(self, r: int, g: int, b: int, a: int) -> None:
+ """Set the source for the r,g,b and a channels of a bitmap
+
+ :param int r: red component source channel. Range 0-7
+ :param int g: green component source channel. Range 0-7
+ :param int b: blue component source channel. Range 0-7
+ :param int a: alpha component source channel. Range 0-7"""
+ ...
+ def BitmapTransformA(self, p: int, v: int) -> None:
+ """Set the :math:`a` component of the bitmap transform matrix
+
+ :param int p: precision control: 0 is 8.8, 1 is 1.15. Range 0-1. The initial value is 0
+ :param int v: The :math:`a` component of the bitmap transform matrix, in signed 8.8 or 1.15 bit fixed-point form. Range 0-131071. The initial value is 256
+
+ The initial value is **p** = 0, **v** = 256. This represents the value 1.0.
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def BitmapTransformB(self, p: int, v: int) -> None:
+ """Set the :math:`b` component of the bitmap transform matrix
+
+ :param int p: precision control: 0 is 8.8, 1 is 1.15. Range 0-1. The initial value is 0
+ :param int v: The :math:`b` component of the bitmap transform matrix, in signed 8.8 or 1.15 bit fixed-point form. Range 0-131071. The initial value is 0
+
+ The initial value is **p** = 0, **v** = 0. This represents the value 0.0.
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def BitmapTransformC(self, v: int) -> None:
+ """Set the :math:`c` component of the bitmap transform matrix
+
+ :param int v: The :math:`c` component of the bitmap transform matrix, in signed 15.8 bit fixed-point form. Range 0-16777215. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def BitmapTransformD(self, p: int, v: int) -> None:
+ """Set the :math:`d` component of the bitmap transform matrix
+
+ :param int p: precision control: 0 is 8.8, 1 is 1.15. Range 0-1. The initial value is 0
+ :param int v: The :math:`d` component of the bitmap transform matrix, in signed 8.8 or 1.15 bit fixed-point form. Range 0-131071. The initial value is 0
+
+ The initial value is **p** = 0, **v** = 0. This represents the value 0.0.
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def BitmapTransformE(self, p: int, v: int) -> None:
+ """Set the :math:`e` component of the bitmap transform matrix
+
+ :param int p: precision control: 0 is 8.8, 1 is 1.15. Range 0-1. The initial value is 0
+ :param int v: The :math:`e` component of the bitmap transform matrix, in signed 8.8 or 1.15 bit fixed-point form. Range 0-131071. The initial value is 256
+
+ The initial value is **p** = 0, **v** = 256. This represents the value 1.0.
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def BitmapTransformF(self, v: int) -> None:
+ """Set the :math:`f` component of the bitmap transform matrix
+
+ :param int v: The :math:`f` component of the bitmap transform matrix, in signed 15.8 bit fixed-point form. Range 0-16777215. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def BlendFunc(self, src: int, dst: int) -> None:
+ """Set pixel arithmetic
+
+ :param int src: specifies how the source blending factor is computed. One of ``ZERO``, ``ONE``, ``SRC_ALPHA``, ``DST_ALPHA``, ``ONE_MINUS_SRC_ALPHA`` or ``ONE_MINUS_DST_ALPHA``. Range 0-7. The initial value is SRC_ALPHA(2)
+ :param int dst: specifies how the destination blending factor is computed, one of the same constants as **src**. Range 0-7. The initial value is ONE_MINUS_SRC_ALPHA(4)
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def Call(self, dest: int) -> None:
+ """Execute a sequence of commands at another location in the display list
+
+ :param int dest: display list address. Range 0-65535"""
+ ...
+ def Cell(self, cell: int) -> None:
+ """Set the bitmap cell number for the vertex2f command
+
+ :param int cell: bitmap cell number. Range 0-127. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def ClearColorA(self, alpha: int) -> None:
+ """Set clear value for the alpha channel
+
+ :param int alpha: alpha value used when the color buffer is cleared. Range 0-255. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def ClearColorRGB(self, red: int, green: int, blue: int) -> None:
+ """Set clear values for red, green and blue channels
+
+ :param int red: red value used when the color buffer is cleared. Range 0-255. The initial value is 0
+ :param int green: green value used when the color buffer is cleared. Range 0-255. The initial value is 0
+ :param int blue: blue value used when the color buffer is cleared. Range 0-255. The initial value is 0
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def Clear(self, c: int, s: int, t: int) -> None:
+ """Clear buffers to preset values
+
+ :param int c: clear color buffer. Range 0-1
+ :param int s: clear stencil buffer. Range 0-1
+ :param int t: clear tag buffer. Range 0-1"""
+ ...
+ def ClearStencil(self, s: int) -> None:
+ """Set clear value for the stencil buffer
+
+ :param int s: value used when the stencil buffer is cleared. Range 0-255. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def ClearTag(self, s: int) -> None:
+ """Set clear value for the tag buffer
+
+ :param int s: value used when the tag buffer is cleared. Range 0-255. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ def ColorA(self, alpha: int) -> None:
+ """Set the current color alpha
+
+ :param int alpha: alpha for the current color. Range 0-255. The initial value is 255
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def ColorMask(self, r: int, g: int, b: int, a: int) -> None:
+ """Enable and disable writing of frame buffer color components
+
+ :param int r: allow updates to the frame buffer red component. Range 0-1. The initial value is 1
+ :param int g: allow updates to the frame buffer green component. Range 0-1. The initial value is 1
+ :param int b: allow updates to the frame buffer blue component. Range 0-1. The initial value is 1
+ :param int a: allow updates to the frame buffer alpha component. Range 0-1. The initial value is 1
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def ColorRGB(self, red: int, green: int, blue: int) -> None:
+ """Set the drawing color
+
+ :param int red: red value for the current color. Range 0-255. The initial value is 255
+ :param int green: green for the current color. Range 0-255. The initial value is 255
+ :param int blue: blue for the current color. Range 0-255. The initial value is 255
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def Display(self) -> None:
+ """End the display list"""
+ ...
+ def End(self) -> None:
+ """End drawing a graphics primitive
+
+ :meth:`Vertex2ii` and :meth:`Vertex2f` calls are ignored until the next :meth:`Begin`."""
+ ...
+ def Jump(self, dest: int) -> None:
+ """Execute commands at another location in the display list
+
+ :param int dest: display list address. Range 0-65535"""
+ ...
+ def LineWidth(self, width: int) -> None:
+ """Set the width of rasterized lines
+
+ :param int width: line width in :math:`1/16` pixel. Range 0-4095. The initial value is 16
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def Macro(self, m: int) -> None:
+ """Execute a single command from a macro register
+
+ :param int m: macro register to read. Range 0-1"""
+ ...
+ def Nop(self) -> None:
+ """No operation"""
+ ...
+ def PaletteSource(self, addr: int) -> None:
+ """Set the base address of the palette
+
+ :param int addr: Address in graphics SRAM, 2-byte aligned. Range 0-4194303. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def PointSize(self, size: int) -> None:
+ """Set the radius of rasterized points
+
+ :param int size: point radius in :math:`1/16` pixel. Range 0-8191. The initial value is 16
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def RestoreContext(self) -> None:
+ """Restore the current graphics context from the context stack"""
+ ...
+ def Return(self) -> None:
+ """Return from a previous call command"""
+ ...
+ def SaveContext(self) -> None:
+ """Push the current graphics context on the context stack"""
+ ...
+ def ScissorSize(self, width: int, height: int) -> None:
+ """Set the size of the scissor clip rectangle
+
+ :param int width: The width of the scissor clip rectangle, in pixels. Range 0-4095. The initial value is hsize
+ :param int height: The height of the scissor clip rectangle, in pixels. Range 0-4095. The initial value is 2048
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def ScissorXY(self, x: int, y: int) -> None:
+ """Set the top left corner of the scissor clip rectangle
+
+ :param int x: The :math:`x` coordinate of the scissor clip rectangle, in pixels. Range 0-2047. The initial value is 0
+ :param int y: The :math:`y` coordinate of the scissor clip rectangle, in pixels. Range 0-2047. The initial value is 0
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def StencilFunc(self, func: int, ref: int, mask: int) -> None:
+ """Set function and reference value for stencil testing
+
+ :param int func: specifies the test function, one of ``NEVER``, ``LESS``, ``LEQUAL``, ``GREATER``, ``GEQUAL``, ``EQUAL``, ``NOTEQUAL``, or ``ALWAYS``. Range 0-7. The initial value is ALWAYS(7)
+ :param int ref: specifies the reference value for the stencil test. Range 0-255. The initial value is 0
+ :param int mask: specifies a mask that is ANDed with the reference value and the stored stencil value. Range 0-255. The initial value is 255
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def StencilMask(self, mask: int) -> None:
+ """Control the writing of individual bits in the stencil planes
+
+ :param int mask: the mask used to enable writing stencil bits. Range 0-255. The initial value is 255
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def StencilOp(self, sfail: int, spass: int) -> None:
+ """Set stencil test actions
+
+ :param int sfail: specifies the action to take when the stencil test fails, one of ``KEEP``, ``ZERO``, ``REPLACE``, ``INCR``, ``INCR_WRAP``, ``DECR``, ``DECR_WRAP``, and ``INVERT``. Range 0-7. The initial value is KEEP(1)
+ :param int spass: specifies the action to take when the stencil test passes, one of the same constants as **sfail**. Range 0-7. The initial value is KEEP(1)
+
+ These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def TagMask(self, mask: int) -> None:
+ """Control the writing of the tag buffer
+
+ :param int mask: allow updates to the tag buffer. Range 0-1. The initial value is 1
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def Tag(self, s: int) -> None:
+ """Set the current tag value
+
+ :param int s: tag value. Range 0-255. The initial value is 255
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def VertexTranslateX(self, x: int) -> None:
+ """Set the vertex transformation's x translation component
+
+ :param int x: signed x-coordinate in :math:`1/16` pixel. Range 0-131071. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def VertexTranslateY(self, y: int) -> None:
+ """Set the vertex transformation's y translation component
+
+ :param int y: signed y-coordinate in :math:`1/16` pixel. Range 0-131071. The initial value is 0
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def VertexFormat(self, frac: int) -> None:
+ """Set the precision of vertex2f coordinates
+
+ :param int frac: Number of fractional bits in X,Y coordinates, 0-4. Range 0-7. The initial value is 4
+
+ This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+ ...
+ def Vertex2ii(self, x: int, y: int, handle: int, cell: int) -> None:
+ """:param int x: x-coordinate in pixels. Range 0-511
+ :param int y: y-coordinate in pixels. Range 0-511
+ :param int handle: bitmap handle. Range 0-31
+ :param int cell: cell number. Range 0-127
+
+ This method is an alternative to :meth:`Vertex2f`."""
+ ...
+ def Vertex2f(self, b: float) -> None:
+ """Draw a point.
+
+ :param float x: pixel x-coordinate
+ :param float y: pixel y-coordinate"""
+ ...
+ def cmd0(self, n: int) -> None:
+ """Append the command word n to the FIFO
+
+ :param int n: The command code
+
+ This method is used by the ``eve`` module to efficiently add
+ commands to the FIFO."""
+ ...
+ def cmd(self, n: int, fmt: str, args: Tuple[str, ...]) -> None:
+ """Append a command packet to the FIFO.
+
+ :param int n: The command code
+ :param str fmt: The command format `struct` layout
+ :param args: The command's arguments
+ :type args: tuple(str, ...)
+
+ Supported format codes: h, H, i, I.
+
+ This method is used by the ``eve`` module to efficiently add
+ commands to the FIFO."""
+ ...
diff --git a/stubs/_pew/__init__.pyi b/stubs/_pew/__init__.pyi
new file mode 100644
index 0000000..03f3e0b
--- /dev/null
+++ b/stubs/_pew/__init__.pyi
@@ -0,0 +1,36 @@
+"""LED matrix driver"""
+
+from __future__ import annotations
+
+from typing import List
+
+import digitalio
+from _typing import ReadableBuffer
+
+class PewPew:
+ """This is an internal module to be used by the ``pew.py`` library from
+ https://github.com/pewpew-game/pew-pewpew-standalone-10.x to handle the
+ LED matrix display and buttons on the ``pewpew10`` board.
+
+ Usage::
+
+ This singleton class is instantiated by the ``pew`` library, and
+ used internally by it. All user-visible interactions are done through
+ that library."""
+
+ def __init__(
+ self,
+ buffer: ReadableBuffer,
+ rows: List[digitalio.DigitalInOut],
+ cols: List[digitalio.DigitalInOut],
+ buttons: digitalio.DigitalInOut,
+ ) -> None:
+ """Initializes matrix scanning routines.
+
+ The ``buffer`` is a 64 byte long ``bytearray`` that stores what should
+ be displayed on the matrix. ``rows`` and ``cols`` are both lists of
+ eight ``DigitalInputOutput`` objects that are connected to the matrix
+ rows and columns. ``buttons`` is a ``DigitalInputOutput`` object that
+ is connected to the common side of all buttons (the other sides of the
+ buttons are connected to rows of the matrix)."""
+ ...
diff --git a/stubs/_pixelbuf/__init__.pyi b/stubs/_pixelbuf/__init__.pyi
new file mode 100644
index 0000000..83a1089
--- /dev/null
+++ b/stubs/_pixelbuf/__init__.pyi
@@ -0,0 +1,108 @@
+"""A fast RGB(W) pixel buffer library for like NeoPixel and DotStar
+
+The `_pixelbuf` module provides the :py:class:`PixelBuf` class to accelerate
+RGB(W) strip/matrix manipulation, such as DotStar and Neopixel.
+
+Byteorders are configured with strings, such as "RGB" or "RGBD"."""
+
+from __future__ import annotations
+
+from typing import List, Tuple, Union, overload
+
+from _typing import ReadableBuffer
+
+def colorwheel(n: float) -> int:
+ """C implementation of the common wheel() function found in many examples.
+ Returns the colorwheel RGB value as an integer value for n (usable in :py:class:`PixelBuf`, neopixel, and dotstar)."""
+ ...
+
+def wheel(n: float) -> int:
+ """Use of wheel() is deprecated. Please use colorwheel()."""
+
+class PixelBuf:
+ """A fast RGB[W] pixel buffer for LED and similar devices."""
+
+ def __init__(
+ self,
+ size: int,
+ *,
+ byteorder: str = "BGR",
+ brightness: float = 0,
+ auto_write: bool = False,
+ header: ReadableBuffer = b"",
+ trailer: ReadableBuffer = b""
+ ) -> None:
+ """Create a PixelBuf object of the specified size, byteorder, and bits per pixel.
+
+ When brightness is less than 1.0, a second buffer will be used to store the color values
+ before they are adjusted for brightness.
+
+ When ``P`` (PWM duration) is present as the 4th character of the byteorder
+ string, the 4th value in the tuple/list for a pixel is the individual pixel
+ brightness (0.0-1.0) and will enable a Dotstar compatible 1st byte for each
+ pixel.
+
+ :param int size: Number of pixels
+ :param str byteorder: Byte order string (such as "RGB", "RGBW" or "PBGR")
+ :param float brightness: Brightness (0 to 1.0, default 1.0)
+ :param bool auto_write: Whether to automatically write pixels (Default False)
+ :param ~_typing.ReadableBuffer header: Sequence of bytes to always send before pixel values.
+ :param ~_typing.ReadableBuffer trailer: Sequence of bytes to always send after pixel values."""
+ ...
+ bpp: int
+ """The number of bytes per pixel in the buffer (read-only)"""
+
+ brightness: float
+ """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."""
+
+ auto_write: bool
+ """Whether to automatically write the pixels after each update."""
+
+ byteorder: str
+ """byteorder string for the buffer (read-only)"""
+ def show(self) -> None:
+ """Transmits the color data to the pixels so that they are shown. This is done automatically
+ when `auto_write` is True."""
+ ...
+ def fill(
+ self, color: Union[int, Tuple[int, int, int], Tuple[int, int, int, float]]
+ ) -> None:
+ """Fills the given pixelbuf with the given color."""
+ ...
+ @overload
+ def __getitem__(
+ self, index: slice
+ ) -> Union[
+ Tuple[Tuple[int, int, int], ...], Tuple[Tuple[int, int, int, float], ...]
+ ]: ...
+ @overload
+ def __getitem__(
+ self, index: int
+ ) -> Union[Tuple[int, int, int], Tuple[int, int, int, float]]:
+ """Returns the pixel value at the given index as a tuple of (Red, Green, Blue[, White]) values
+ between 0 and 255. When in PWM (DotStar) mode, the 4th tuple value is a float of the pixel
+ intensity from 0-1.0."""
+ ...
+ @overload
+ def __setitem__(
+ self,
+ index: slice,
+ value: Tuple[Union[int, Tuple[float, ...], List[float]], ...],
+ ) -> None: ...
+ @overload
+ def __setitem__(
+ self, index: slice, value: List[Union[int, Tuple[float, ...], List[float]]]
+ ) -> None: ...
+ @overload
+ def __setitem__(
+ self, index: int, value: Union[int, Tuple[float, ...], List[float]]
+ ) -> None:
+ """Sets the pixel value at the given index. Value can either be a tuple or integer. Tuples are
+ The individual (Red, Green, Blue[, White]) values between 0 and 255. If given an integer, the
+ red, green and blue values are packed into the lower three bytes (0xRRGGBB).
+ For RGBW byteorders, if given only RGB values either as an int or as a tuple, the white value
+ is used instead when the red, green, and blue values are the same."""
+ ...
diff --git a/stubs/_stage/__init__.pyi b/stubs/_stage/__init__.pyi
new file mode 100644
index 0000000..31fb514
--- /dev/null
+++ b/stubs/_stage/__init__.pyi
@@ -0,0 +1,102 @@
+"""C-level helpers for animation of sprites on a stage
+
+The `_stage` module contains native code to speed-up the ```stage`` Library
+`_."""
+
+from __future__ import annotations
+
+from typing import List
+
+import displayio
+from _typing import ReadableBuffer, WriteableBuffer
+
+def render(
+ x0: int,
+ y0: int,
+ x1: int,
+ y1: int,
+ layers: List[Layer],
+ buffer: WriteableBuffer,
+ display: displayio.Display,
+ scale: int,
+ background: int,
+) -> None:
+ """Render and send to the display a fragment of the screen.
+
+ :param int x0: Left edge of the fragment.
+ :param int y0: Top edge of the fragment.
+ :param int x1: Right edge of the fragment.
+ :param int y1: Bottom edge of the fragment.
+ :param layers: A list of the :py:class:`~_stage.Layer` objects.
+ :type layers: list[Layer]
+ :param ~_typing.WriteableBuffer buffer: A buffer to use for rendering.
+ :param ~displayio.Display display: The display to use.
+ :param int scale: How many times should the image be scaled up.
+ :param int background: What color to display when nothing is there.
+
+ There are also no sanity checks, outside of the basic overflow
+ checking. The caller is responsible for making the passed parameters
+ valid.
+
+ This function is intended for internal use in the ``stage`` library
+ and all the necessary checks are performed there."""
+
+class Layer:
+ """Keep information about a single layer of graphics"""
+
+ def __init__(
+ self,
+ width: int,
+ height: int,
+ graphic: ReadableBuffer,
+ palette: ReadableBuffer,
+ grid: ReadableBuffer,
+ ) -> None:
+ """Keep internal information about a layer of graphics (either a
+ ``Grid`` or a ``Sprite``) in a format suitable for fast rendering
+ with the ``render()`` function.
+
+ :param int width: The width of the grid in tiles, or 1 for sprites.
+ :param int height: The height of the grid in tiles, or 1 for sprites.
+ :param ~_typing.ReadableBuffer graphic: The graphic data of the tiles.
+ :param ~_typing.ReadableBuffer palette: The color palette to be used.
+ :param ~_typing.ReadableBuffer grid: The contents of the grid map.
+
+ This class is intended for internal use in the ``stage`` library and
+ it shouldn't be used on its own."""
+ ...
+ def move(self, x: int, y: int) -> None:
+ """Set the offset of the layer to the specified values."""
+ ...
+ def frame(self, frame: int, rotation: int) -> None:
+ """Set the animation frame of the sprite, and optionally rotation its
+ graphic."""
+ ...
+
+class Text:
+ """Keep information about a single grid of text"""
+
+ def __init__(
+ self,
+ width: int,
+ height: int,
+ font: ReadableBuffer,
+ palette: ReadableBuffer,
+ chars: ReadableBuffer,
+ ) -> None:
+ """Keep internal information about a grid of text
+ in a format suitable for fast rendering
+ with the ``render()`` function.
+
+ :param int width: The width of the grid in tiles, or 1 for sprites.
+ :param int height: The height of the grid in tiles, or 1 for sprites.
+ :param ~_typing.ReadableBuffer font: The font data of the characters.
+ :param ~_typing.ReadableBuffer palette: The color palette to be used.
+ :param ~_typing.ReadableBuffer chars: The contents of the character grid.
+
+ This class is intended for internal use in the ``stage`` library and
+ it shouldn't be used on its own."""
+ ...
+ def move(self, x: int, y: int) -> None:
+ """Set the offset of the text to the specified values."""
+ ...
diff --git a/stubs/_typing/__init__.pyi b/stubs/_typing/__init__.pyi
new file mode 100644
index 0000000..120c4f4
--- /dev/null
+++ b/stubs/_typing/__init__.pyi
@@ -0,0 +1,68 @@
+"""Types for the C-level protocols"""
+
+from __future__ import annotations
+
+import array
+from typing import Union
+
+import alarm
+import alarm.pin
+import alarm.time
+import audiocore
+import audiomixer
+import audiomp3
+import rgbmatrix
+import ulab
+
+ReadableBuffer = Union[
+ bytes, bytearray, memoryview, array.array, ulab.array, rgbmatrix.RGBMatrix
+]
+"""Classes that implement the readable buffer protocol
+
+ - `bytes`
+ - `bytearray`
+ - `memoryview`
+ - `array.array`
+ - `ulab.array`
+ - `rgbmatrix.RGBMatrix`
+"""
+
+WriteableBuffer = Union[
+ bytearray, memoryview, array.array, ulab.array, rgbmatrix.RGBMatrix
+]
+"""Classes that implement the writeable buffer protocol
+
+ - `bytearray`
+ - `memoryview`
+ - `array.array`
+ - `ulab.array`
+ - `rgbmatrix.RGBMatrix`
+"""
+
+AudioSample = Union[
+ audiocore.WaveFile, audiocore.RawSample, audiomixer.Mixer, audiomp3.MP3Decoder
+]
+"""Classes that implement the audiosample protocol
+
+ - `audiocore.WaveFile`
+ - `audiocore.RawSample`
+ - `audiomixer.Mixer`
+ - `audiomp3.MP3Decoder`
+
+ You can play these back with `audioio.AudioOut`, `audiobusio.I2SOut` or `audiopwmio.PWMAudioOut`.
+"""
+
+FrameBuffer = Union[rgbmatrix.RGBMatrix]
+"""Classes that implement the framebuffer protocol
+
+ - `rgbmatrix.RGBMatrix`
+"""
+
+Alarm = Union[alarm.pin.PinAlarm, alarm.time.TimeAlarm]
+"""Classes that implement alarms for sleeping and asynchronous notification.
+
+ - `alarm.pin.PinAlarm`
+ - `alarm.time.TimeAlarm`
+
+ You can use these alarms to wake up from light or deep sleep.
+"""
diff --git a/stubs/adafruit_bus_device/__init__.pyi b/stubs/adafruit_bus_device/__init__.pyi
new file mode 100644
index 0000000..21eb871
--- /dev/null
+++ b/stubs/adafruit_bus_device/__init__.pyi
@@ -0,0 +1,133 @@
+"""Hardware accelerated external bus access
+
+The I2CDevice and SPIDevice helper classes make managing transaction state on a bus easy.
+For example, they manage locking the bus to prevent other concurrent access. For SPI
+devices, it manages the chip select and protocol changes such as mode. For I2C, it
+manages the device address."""
+
+from __future__ import annotations
+
+import busio
+import microcontroller
+from _typing import ReadableBuffer, WriteableBuffer
+
+class I2CDevice:
+ """I2C Device Manager"""
+
+ def __init__(self, i2c: busio.I2C, device_address: int, probe: bool = True) -> None:
+
+ """Represents a single I2C device and manages locking the bus and the device
+ address.
+ :param ~busio.I2C i2c: The I2C bus the device is on
+ :param int device_address: The 7 bit device address
+ :param bool probe: Probe for the device upon object creation, default is true
+
+ Example::
+
+ import busio
+ from board import *
+ from adafruit_bus_device.i2c_device import I2CDevice
+ with busio.I2C(SCL, SDA) as i2c:
+ device = I2CDevice(i2c, 0x70)
+ bytes_read = bytearray(4)
+ with device:
+ device.readinto(bytes_read)
+ # A second transaction
+ with device:
+ device.write(bytes_read)"""
+ ...
+ def __enter__(self) -> I2CDevice:
+ """Context manager entry to lock bus."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically unlocks the bus on exit."""
+ ...
+ def readinto(self, buf: WriteableBuffer, *, start: int = 0, end: int = 0) -> None:
+ """Read into ``buf`` from the device. The number of bytes read will be the
+ length of ``buf``.
+ If ``start`` or ``end`` is provided, then the buffer will be sliced
+ as if ``buf[start:end]``. This will not cause an allocation like
+ ``buf[start:end]`` will so it saves memory.
+ :param bytearray buf: buffer to write into
+ :param int start: Index to start writing at
+ :param int end: Index to write up to but not include; if None, use ``len(buf)``"""
+ ...
+ def write(self, buf: ReadableBuffer, *, start: int = 0, end: int = 0) -> None:
+ """Write the bytes from ``buffer`` to the device, then transmit a stop bit.
+ If ``start`` or ``end`` is provided, then the buffer will be sliced
+ as if ``buffer[start:end]``. This will not cause an allocation like
+ ``buffer[start:end]`` will so it saves memory.
+ :param bytearray buf: buffer containing the bytes to write
+ :param int start: Index to start writing from
+ :param int end: Index to read up to but not include; if None, use ``len(buf)``
+ """
+ ...
+ def write_then_readinto(
+ self,
+ out_buffer: WriteableBuffer,
+ in_buffer: ReadableBuffer,
+ *,
+ out_start: int = 0,
+ out_end: int = 0,
+ in_start: int = 0,
+ in_end: int = 0
+ ) -> None:
+ """Write the bytes from ``out_buffer`` to the device, then immediately
+ reads into ``in_buffer`` from the device. The number of bytes read
+ will be the length of ``in_buffer``.
+ If ``out_start`` or ``out_end`` is provided, then the output buffer
+ will be sliced as if ``out_buffer[out_start:out_end]``. This will
+ not cause an allocation like ``buffer[out_start:out_end]`` will so
+ it saves memory.
+ If ``in_start`` or ``in_end`` is provided, then the input buffer
+ will be sliced as if ``in_buffer[in_start:in_end]``. This will not
+ cause an allocation like ``in_buffer[in_start:in_end]`` will so
+ it saves memory.
+ :param bytearray out_buffer: buffer containing the bytes to write
+ :param bytearray in_buffer: buffer containing the bytes to read into
+ :param int out_start: Index to start writing from
+ :param int out_end: Index to read up to but not include; if None, use ``len(out_buffer)``
+ :param int in_start: Index to start writing at
+ :param int in_end: Index to write up to but not include; if None, use ``len(in_buffer)``
+ """
+ ...
+
+class SPIDevice:
+ """SPI Device Manager"""
+
+ def __init__(
+ self,
+ spi: busio.SPI,
+ chip_select: microcontroller.Pin,
+ *,
+ baudrate: int = 100000,
+ polarity: int = 0,
+ phase: int = 0,
+ extra_clocks: int = 0
+ ) -> None:
+
+ """
+ Represents a single SPI device and manages locking the bus and the device address.
+ :param ~busio.SPI spi: The SPI bus the device is on
+ :param ~digitalio.DigitalInOut chip_select: The chip select pin object that implements the DigitalInOut API.
+ :param int extra_clocks: The minimum number of clock cycles to cycle the bus after CS is high. (Used for SD cards.)
+
+ Example::
+
+ import busio
+ import digitalio
+ from board import *
+ from adafruit_bus_device.spi_device import SPIDevice
+ with busio.SPI(SCK, MOSI, MISO) as spi_bus:
+ cs = digitalio.DigitalInOut(D10)
+ device = SPIDevice(spi_bus, cs)
+ bytes_read = bytearray(4)
+ # The object assigned to spi in the with statements below
+ # is the original spi_bus object. We are using the busio.SPI
+ # operations busio.SPI.readinto() and busio.SPI.write().
+ with device as spi:
+ spi.readinto(bytes_read)
+ # A second transaction
+ with device as spi:
+ spi.write(bytes_read)"""
+ ...
diff --git a/stubs/aesio/__init__.pyi b/stubs/aesio/__init__.pyi
new file mode 100644
index 0000000..e917065
--- /dev/null
+++ b/stubs/aesio/__init__.pyi
@@ -0,0 +1,55 @@
+"""AES encryption routines
+
+The `AES` module contains classes used to implement encryption
+and decryption. It aims to be low overhead in terms of memory."""
+
+from __future__ import annotations
+
+from typing import Optional
+
+from _typing import ReadableBuffer, WriteableBuffer
+
+class AES:
+ """Encrypt and decrypt AES streams"""
+
+ def __init__(
+ self,
+ key: ReadableBuffer,
+ mode: int = 0,
+ iv: Optional[ReadableBuffer] = None,
+ segment_size: int = 8,
+ ) -> None:
+ """Create a new AES state with the given key.
+
+ :param ~_typing.ReadableBuffer key: A 16-, 24-, or 32-byte key
+ :param int mode: AES mode to use. One of: AES.MODE_ECB, AES.MODE_CBC, or
+ AES.MODE_CTR
+ :param ~_typing.ReadableBuffer iv: Initialization vector to use for CBC or CTR mode
+
+ Additional arguments are supported for legacy reasons.
+
+ Encrypting a string::
+
+ import aesio
+ from binascii import hexlify
+
+ key = b'Sixteen byte key'
+ inp = b'Circuit Python!!' # Note: 16-bytes long
+ outp = bytearray(len(inp))
+ cipher = aesio.AES(key, aesio.mode.MODE_ECB)
+ cipher.encrypt_into(inp, outp)
+ hexlify(outp)"""
+ ...
+ def encrypt_into(self, src: ReadableBuffer, dest: WriteableBuffer) -> None:
+ """Encrypt the buffer from ``src`` into ``dest``.
+
+ For ECB mode, the buffers must be 16 bytes long. For CBC mode, the
+ buffers must be a multiple of 16 bytes, and must be equal length. For
+ CTX mode, there are no restrictions."""
+ ...
+ def decrypt_into(self, src: ReadableBuffer, dest: WriteableBuffer) -> None:
+ """Decrypt the buffer from ``src`` into ``dest``.
+ For ECB mode, the buffers must be 16 bytes long. For CBC mode, the
+ buffers must be a multiple of 16 bytes, and must be equal length. For
+ CTX mode, there are no restrictions."""
+ ...
diff --git a/stubs/alarm/__init__.pyi b/stubs/alarm/__init__.pyi
new file mode 100644
index 0000000..d5b0c34
--- /dev/null
+++ b/stubs/alarm/__init__.pyi
@@ -0,0 +1,116 @@
+"""Alarms and sleep
+
+Provides alarms that trigger based on time intervals or on external events, such as pin
+changes.
+The program can simply wait for these alarms, or go to sleep and be awoken when they trigger.
+
+There are two supported levels of sleep: light sleep and deep sleep.
+
+Light sleep keeps sufficient state so the program can resume after sleeping.
+It does not shut down WiFi, BLE, or other communications, or ongoing activities such
+as audio playback. It reduces power consumption to the extent possible that leaves
+these continuing activities running. In some cases there may be no decrease in power consumption.
+
+Deep sleep shuts down power to nearly all of the microcontroller including the CPU and RAM. This can save
+a more significant amount of power, but CircuitPython must restart ``code.py`` from the beginning when
+awakened.
+
+For both light sleep and deep sleep, if CircuitPython is connected to a host computer,
+maintaining the connection takes priority and power consumption may not be reduced.
+"""
+
+from __future__ import annotations
+
+from typing import overload
+
+from _typing import Alarm, ReadableBuffer
+
+sleep_memory: SleepMemory
+"""Memory that persists during deep sleep.
+This object is the sole instance of `alarm.SleepMemory`."""
+
+wake_alarm: Alarm
+"""The most recently triggered alarm. If CircuitPython was sleeping, the alarm the woke it from sleep."""
+
+def light_sleep_until_alarms(*alarms: Alarm) -> Alarm:
+ """Go into a light sleep until awakened one of the alarms. The alarm causing the wake-up
+ is returned, and is also available as `alarm.wake_alarm`.
+
+ If no alarms are specified, return immediately.
+
+ **If CircuitPython is connected to a host computer, the connection will be maintained,
+ and the microcontroller may not actually go into a light sleep.**
+ This allows the user to interrupt an existing program with ctrl-C,
+ and to edit the files in CIRCUITPY, which would not be possible in true light sleep.
+ Thus, to use light sleep and save significant power,
+ """
+ ...
+
+def exit_and_deep_sleep_until_alarms(*alarms: Alarm) -> None:
+ """Exit the program and go into a deep sleep, until awakened by one of the alarms.
+ This function does not return.
+
+ When awakened, the microcontroller will restart and will run ``boot.py`` and ``code.py``
+ from the beginning.
+
+ After restart, an alarm *equivalent* to the one that caused the wake-up
+ will be available as `alarm.wake_alarm`.
+ Its type and/or attributes may not correspond exactly to the original alarm.
+ For time-base alarms, currently, an `alarm.time.TimeAlarm()` is created.
+
+ If no alarms are specified, the microcontroller will deep sleep until reset.
+
+ **If CircuitPython is connected to a host computer, the connection will be maintained,
+ and the system will not go into deep sleep.**
+ This allows the user to interrupt an existing program with ctrl-C,
+ and to edit the files in CIRCUITPY, which would not be possible in true deep sleep.
+ Thus, to use deep sleep and save significant power, you will need to disconnect from the host.
+
+ Here is skeletal example that deep-sleeps and restarts every 60 seconds:
+
+ .. code-block:: python
+
+ import alarm
+ import time
+
+ print("Waking up")
+
+ # Set an alarm for 60 seconds from now.
+ time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 60)
+
+ # Deep sleep until the alarm goes off. Then restart the program.
+ alarm.exit_and_deep_sleep_until_alarms(time_alarm)
+ """
+ ...
+
+class SleepMemory:
+ """Store raw bytes in RAM that persists during deep sleep.
+ The class acts as a ``bytearray``.
+ If power is lost, the memory contents are lost.
+
+ Note that this class can't be imported and used directly. The sole
+ instance of :class:`SleepMemory` is available at
+ :attr:`alarm.sleep_memory`.
+
+ Usage::
+
+ import alarm
+ alarm.sleep_memory[0] = True
+ alarm.sleep_memory[1] = 12
+ """
+
+ def __init__(self) -> None:
+ """Not used. Access the sole instance through `alarm.sleep_memory`."""
+ ...
+ @overload
+ def __getitem__(self, index: slice) -> bytearray: ...
+ @overload
+ def __getitem__(self, index: int) -> int:
+ """Returns the value at the given index."""
+ ...
+ @overload
+ def __setitem__(self, index: slice, value: ReadableBuffer) -> None: ...
+ @overload
+ def __setitem__(self, index: int, value: int) -> None:
+ """Set the value at the given index."""
+ ...
diff --git a/stubs/alarm/pin/__init__.pyi b/stubs/alarm/pin/__init__.pyi
new file mode 100644
index 0000000..7d89280
--- /dev/null
+++ b/stubs/alarm/pin/__init__.pyi
@@ -0,0 +1,39 @@
+from __future__ import annotations
+
+import microcontroller
+
+class PinAlarm:
+ """Trigger an alarm when a pin changes state."""
+
+ def __init__(
+ self,
+ pin: microcontroller.Pin,
+ value: bool,
+ edge: bool = False,
+ pull: bool = False,
+ ) -> None:
+ """Create an alarm triggered by a `microcontroller.Pin` level. The alarm is not active
+ until it is passed to an `alarm`-enabling function, such as `alarm.light_sleep_until_alarms()` or
+ `alarm.exit_and_deep_sleep_until_alarms()`.
+
+ :param microcontroller.Pin pin: The pin to monitor. On some ports, the choice of pin
+ may be limited due to hardware restrictions, particularly for deep-sleep alarms.
+ :param bool value: When active, trigger when the pin value is high (``True``) or low (``False``).
+ On some ports, multiple `PinAlarm` objects may need to have coordinated values
+ for deep-sleep alarms.
+ :param bool edge: If ``True``, trigger only when there is a transition to the specified
+ value of ``value``. If ``True``, if the alarm becomes active when the pin value already
+ matches ``value``, the alarm is not triggered: the pin must transition from ``not value``
+ to ``value`` to trigger the alarm. On some ports, edge-triggering may not be available,
+ particularly for deep-sleep alarms.
+ :param bool pull: Enable a pull-up or pull-down which pulls the pin to the level opposite
+ that of ``value``. For instance, if ``value`` is set to ``True``, setting ``pull``
+ to ``True`` will enable a pull-down, to hold the pin low normally until an outside signal
+ pulls it high.
+ """
+ ...
+ pin: microcontroller.Pin
+ """The trigger pin."""
+
+ value: bool
+ """The value on which to trigger."""
diff --git a/stubs/alarm/time/__init__.pyi b/stubs/alarm/time/__init__.pyi
new file mode 100644
index 0000000..7f417e5
--- /dev/null
+++ b/stubs/alarm/time/__init__.pyi
@@ -0,0 +1,26 @@
+from __future__ import annotations
+
+from typing import Optional
+
+class TimeAlarm:
+ """Trigger an alarm when the specified time is reached."""
+
+ def __init__(
+ self, monotonic_time: Optional[float] = None, epoch_time: Optional[int] = None
+ ) -> None:
+ """Create an alarm that will be triggered when `time.monotonic()` would equal
+ ``monotonic_time``, or when `time.time()` would equal ``epoch_time``.
+ Only one of the two arguments can be given.
+ The alarm is not active until it is passed to an
+ `alarm`-enabling function, such as `alarm.light_sleep_until_alarms()` or
+ `alarm.exit_and_deep_sleep_until_alarms()`.
+
+ If the given time is in the past when sleep occurs, the alarm will be triggered
+ immediately.
+ """
+ ...
+ monotonic_time: float
+ """When this time is reached, the alarm will trigger, based on the `time.monotonic()` clock.
+ The time may be given as ``epoch_time`` in the constructor, but it is returned
+ by this property only as a `time.monotonic()` time.
+ """
diff --git a/stubs/analogio/__init__.pyi b/stubs/analogio/__init__.pyi
new file mode 100644
index 0000000..93fb14d
--- /dev/null
+++ b/stubs/analogio/__init__.pyi
@@ -0,0 +1,99 @@
+"""Analog hardware support
+
+The `analogio` module contains classes to provide access to analog IO
+typically implemented with digital-to-analog (DAC) and analog-to-digital
+(ADC) converters.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+For example::
+
+ import analogio
+ from board import *
+
+ pin = analogio.AnalogIn(A0)
+ print(pin.value)
+ pin.deinit()
+
+This example will initialize the the device, read
+:py:data:`~analogio.AnalogIn.value` and then
+:py:meth:`~analogio.AnalogIn.deinit` the hardware. The last step is optional
+because CircuitPython will do it automatically after the program finishes."""
+
+from __future__ import annotations
+
+from typing import Optional
+
+import microcontroller
+
+class AnalogIn:
+ """Read analog voltage levels
+
+ Usage::
+
+ import analogio
+ from board import *
+
+ adc = analogio.AnalogIn(A1)
+ val = adc.value"""
+
+ def __init__(self, pin: microcontroller.Pin) -> None:
+ """Use the AnalogIn on the given pin. The reference voltage varies by
+ platform so use ``reference_voltage`` to read the configured setting.
+
+ :param ~microcontroller.Pin pin: the pin to read from"""
+ ...
+ def deinit(self) -> None:
+ """Turn off the AnalogIn and release the pin for other use."""
+ ...
+ def __enter__(self) -> AnalogIn:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ value: int
+ """The value on the analog pin between 0 and 65535 inclusive (16-bit). (read-only)
+
+ Even if the underlying analog to digital converter (ADC) is lower
+ resolution, the value is 16-bit."""
+
+ reference_voltage: Optional[float]
+ """The maximum voltage measurable (also known as the reference voltage) as a
+ `float` in Volts."""
+
+class AnalogOut:
+ """Output analog values (a specific voltage).
+
+ Example usage::
+
+ import analogio
+ from microcontroller import pin
+
+ dac = analogio.AnalogOut(pin.PA02) # output on pin PA02
+ dac.value = 32768 # makes PA02 1.65V"""
+
+ def __init__(self, pin: microcontroller.Pin) -> None:
+ """Use the AnalogOut on the given pin.
+
+ :param ~microcontroller.Pin pin: the pin to output to"""
+ ...
+ def deinit(self) -> None:
+ """Turn off the AnalogOut and release the pin for other use."""
+ ...
+ def __enter__(self) -> AnalogOut:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ value: int
+ """The value on the analog pin between 0 and 65535 inclusive (16-bit). (write-only)
+
+ Even if the underlying digital to analog converter (DAC) is lower
+ resolution, the value is 16-bit."""
diff --git a/stubs/audiobusio/__init__.pyi b/stubs/audiobusio/__init__.pyi
new file mode 100644
index 0000000..972a929
--- /dev/null
+++ b/stubs/audiobusio/__init__.pyi
@@ -0,0 +1,188 @@
+"""Support for audio input and output over digital buses
+
+The `audiobusio` module contains classes to provide access to audio IO
+over digital buses. These protocols are used to communicate audio to other
+chips in the same circuit. It doesn't include audio interconnect protocols
+such as S/PDIF.
+
+All libraries change hardware state and should be deinitialized when they
+are no longer needed. To do so, either call :py:meth:`!deinit` or use a
+context manager."""
+
+from __future__ import annotations
+
+import _typing
+import microcontroller
+from _typing import WriteableBuffer
+
+class I2SOut:
+ """Output an I2S audio signal"""
+
+ def __init__(
+ self,
+ bit_clock: microcontroller.Pin,
+ word_select: microcontroller.Pin,
+ data: microcontroller.Pin,
+ *,
+ left_justified: bool
+ ) -> None:
+ """Create a I2SOut object associated with the given pins.
+
+ :param ~microcontroller.Pin bit_clock: The bit clock (or serial clock) pin
+ :param ~microcontroller.Pin word_select: The word select (or left/right clock) pin
+ :param ~microcontroller.Pin data: The data pin
+ :param bool left_justified: True when data bits are aligned with the word select clock. False
+ when they are shifted by one to match classic I2S protocol.
+
+ Simple 8ksps 440 Hz sine wave on `Metro M0 Express `_
+ using `UDA1334 Breakout `_::
+
+ import audiobusio
+ import audiocore
+ import board
+ import array
+ import time
+ import math
+
+ # Generate one period of sine wave.
+ length = 8000 // 440
+ sine_wave = array.array("H", [0] * length)
+ for i in range(length):
+ sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15)
+
+ sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000)
+ i2s = audiobusio.I2SOut(board.D1, board.D0, board.D9)
+ i2s.play(sine_wave, loop=True)
+ time.sleep(1)
+ i2s.stop()
+
+ Playing a wave file from flash::
+
+ import board
+ import audioio
+ import audiocore
+ import audiobusio
+ import digitalio
+
+
+ f = open("cplay-5.1-16bit-16khz.wav", "rb")
+ wav = audiocore.WaveFile(f)
+
+ a = audiobusio.I2SOut(board.D1, board.D0, board.D9)
+
+ print("playing")
+ a.play(wav)
+ while a.playing:
+ pass
+ print("stopped")"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the I2SOut and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> I2SOut:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def play(self, sample: _typing.AudioSample, *, loop: bool = False) -> None:
+ """Plays the sample once when loop=False and continuously when loop=True.
+ Does not block. Use `playing` to block.
+
+ Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+
+ The sample itself should consist of 8 bit or 16 bit samples."""
+ ...
+ def stop(self) -> None:
+ """Stops playback."""
+ ...
+ playing: bool
+ """True when the audio sample is being output. (read-only)"""
+ def pause(self) -> None:
+ """Stops playback temporarily while remembering the position. Use `resume` to resume playback."""
+ ...
+ def resume(self) -> None:
+ """Resumes sample playback after :py:func:`pause`."""
+ ...
+ paused: bool
+ """True when playback is paused. (read-only)"""
+
+class PDMIn:
+ """Record an input PDM audio stream"""
+
+ def __init__(
+ self,
+ clock_pin: microcontroller.Pin,
+ data_pin: microcontroller.Pin,
+ *,
+ sample_rate: int = 16000,
+ bit_depth: int = 8,
+ mono: bool = True,
+ oversample: int = 64,
+ startup_delay: float = 0.11
+ ) -> None:
+ """Create a PDMIn object associated with the given pins. This allows you to
+ record audio signals from the given pins. Individual ports may put further
+ restrictions on the recording parameters. The overall sample rate is
+ determined by `sample_rate` x ``oversample``, and the total must be 1MHz or
+ higher, so `sample_rate` must be a minimum of 16000.
+
+ :param ~microcontroller.Pin clock_pin: The pin to output the clock to
+ :param ~microcontroller.Pin data_pin: The pin to read the data from
+ :param int sample_rate: Target sample_rate of the resulting samples. Check `sample_rate` for actual value.
+ Minimum sample_rate is about 16000 Hz.
+ :param int bit_depth: Final number of bits per sample. Must be divisible by 8
+ :param bool mono: True when capturing a single channel of audio, captures two channels otherwise
+ :param int oversample: Number of single bit samples to decimate into a final sample. Must be divisible by 8
+ :param float startup_delay: seconds to wait after starting microphone clock
+ to allow microphone to turn on. Most require only 0.01s; some require 0.1s. Longer is safer.
+ Must be in range 0.0-1.0 seconds."""
+
+ """Record 8-bit unsigned samples to buffer::
+
+ import audiobusio
+ import board
+
+ # Prep a buffer to record into
+ b = bytearray(200)
+ with audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA, sample_rate=16000) as mic:
+ mic.record(b, len(b))
+
+ Record 16-bit unsigned samples to buffer::
+
+ import audiobusio
+ import board
+
+ # Prep a buffer to record into. The array interface doesn't allow for
+ # constructing with a set size so we append to it until we have the size
+ # we want.
+ b = array.array("H")
+ for i in range(200):
+ b.append(0)
+ with audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA, sample_rate=16000, bit_depth=16) as mic:
+ mic.record(b, len(b))"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the PDMIn and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> PDMIn:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context."""
+ ...
+ def record(self, destination: WriteableBuffer, destination_length: int) -> None:
+ """Records destination_length bytes of samples to destination. This is
+ blocking.
+
+ An IOError may be raised when the destination is too slow to record the
+ audio at the given rate. For internal flash, writing all 1s to the file
+ before recording is recommended to speed up writes.
+
+ :return: The number of samples recorded. If this is less than ``destination_length``,
+ some samples were missed due to processing time."""
+ ...
+ sample_rate: int
+ """The actual sample_rate of the recording. This may not match the constructed
+ sample rate due to internal clock limitations."""
diff --git a/stubs/audiocore/__init__.pyi b/stubs/audiocore/__init__.pyi
new file mode 100644
index 0000000..e924fa2
--- /dev/null
+++ b/stubs/audiocore/__init__.pyi
@@ -0,0 +1,116 @@
+"""Support for audio samples"""
+
+from __future__ import annotations
+
+import typing
+from typing import Optional
+
+from _typing import ReadableBuffer, WriteableBuffer
+
+class RawSample:
+ """A raw audio sample buffer in memory"""
+
+ def __init__(
+ self, buffer: ReadableBuffer, *, channel_count: int = 1, sample_rate: int = 8000
+ ) -> None:
+ """Create a RawSample based on the given buffer of signed values. If channel_count is more than
+ 1 then each channel's samples should alternate. In other words, for a two channel buffer, the
+ first sample will be for channel 1, the second sample will be for channel two, the third for
+ channel 1 and so on.
+
+ :param ~_typing.ReadableBuffer buffer: A buffer with samples
+ :param int channel_count: The number of channels in the buffer
+ :param int sample_rate: The desired playback sample rate
+
+ Simple 8ksps 440 Hz sin wave::
+
+ import audiocore
+ import audioio
+ import board
+ import array
+ import time
+ import math
+
+ # Generate one period of sine wav.
+ length = 8000 // 440
+ sine_wave = array.array("h", [0] * length)
+ for i in range(length):
+ sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15))
+
+ dac = audioio.AudioOut(board.SPEAKER)
+ sine_wave = audiocore.RawSample(sine_wave)
+ dac.play(sine_wave, loop=True)
+ time.sleep(1)
+ dac.stop()"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the AudioOut and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> RawSample:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ sample_rate: Optional[int]
+ """32 bit value that dictates how quickly samples are played in Hertz (cycles per second).
+ When the sample is looped, this can change the pitch output without changing the underlying
+ sample. This will not change the sample rate of any active playback. Call ``play`` again to
+ change it."""
+
+class WaveFile:
+ """Load a wave file for audio playback
+
+ A .wav file prepped for audio playback. Only mono and stereo files are supported. Samples must
+ be 8 bit unsigned or 16 bit signed. If a buffer is provided, it will be used instead of allocating
+ an internal buffer."""
+
+ def __init__(self, file: typing.BinaryIO, buffer: WriteableBuffer) -> None:
+ """Load a .wav file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`.
+
+ :param typing.BinaryIO file: Already opened wave file
+ :param ~_typing.WriteableBuffer buffer: Optional pre-allocated buffer, that will be split in half and used for double-buffering of the data. If not provided, two 512 byte buffers are allocated internally.
+
+
+ Playing a wave file from flash::
+
+ import board
+ import audiocore
+ import audioio
+ import digitalio
+
+ # Required for CircuitPlayground Express
+ speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
+ speaker_enable.switch_to_output(value=True)
+
+ data = open("cplay-5.1-16bit-16khz.wav", "rb")
+ wav = audiocore.WaveFile(data)
+ a = audioio.AudioOut(board.A0)
+
+ print("playing")
+ a.play(wav)
+ while a.playing:
+ pass
+ print("stopped")"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the WaveFile and releases all memory resources for reuse."""
+ ...
+ def __enter__(self) -> WaveFile:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ sample_rate: int
+ """32 bit value that dictates how quickly samples are loaded into the DAC
+ in Hertz (cycles per second). When the sample is looped, this can change
+ the pitch output without changing the underlying sample."""
+
+ bits_per_sample: int
+ """Bits per sample. (read only)"""
+
+ channel_count: int
+ """Number of audio channels. (read only)"""
diff --git a/stubs/audioio/__init__.pyi b/stubs/audioio/__init__.pyi
new file mode 100644
index 0000000..4d9dd53
--- /dev/null
+++ b/stubs/audioio/__init__.pyi
@@ -0,0 +1,115 @@
+"""Support for audio output
+
+The `audioio` module contains classes to provide access to audio IO.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+Since CircuitPython 5, `RawSample` and `WaveFile` are moved
+to :mod:`audiocore`, and `Mixer` is moved to :mod:`audiomixer`.
+
+For compatibility with CircuitPython 4.x, some builds allow the items in
+`audiocore` to be imported from `audioio`. This will be removed for all
+boards in a future build of CircuitPython."""
+
+from __future__ import annotations
+
+from typing import Optional
+
+import _typing
+import microcontroller
+
+class AudioOut:
+ """Output an analog audio signal"""
+
+ def __init__(
+ self,
+ left_channel: microcontroller.Pin,
+ *,
+ right_channel: Optional[microcontroller.Pin] = None,
+ quiescent_value: int = 0x8000
+ ) -> None:
+ """Create a AudioOut object associated with the given pin(s). This allows you to
+ play audio signals out on the given pin(s).
+
+ :param ~microcontroller.Pin left_channel: The pin to output the left channel to
+ :param ~microcontroller.Pin right_channel: The pin to output the right channel to
+ :param int quiescent_value: The output value when no signal is present. Samples should start
+ and end with this value to prevent audible popping.
+
+ Simple 8ksps 440 Hz sin wave::
+
+ import audiocore
+ import audioio
+ import board
+ import array
+ import time
+ import math
+
+ # Generate one period of sine wav.
+ length = 8000 // 440
+ sine_wave = array.array("H", [0] * length)
+ for i in range(length):
+ sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15)
+
+ dac = audioio.AudioOut(board.SPEAKER)
+ sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000)
+ dac.play(sine_wave, loop=True)
+ time.sleep(1)
+ dac.stop()
+
+ Playing a wave file from flash::
+
+ import board
+ import audioio
+ import digitalio
+
+ # Required for CircuitPlayground Express
+ speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
+ speaker_enable.switch_to_output(value=True)
+
+ data = open("cplay-5.1-16bit-16khz.wav", "rb")
+ wav = audiocore.WaveFile(data)
+ a = audioio.AudioOut(board.A0)
+
+ print("playing")
+ a.play(wav)
+ while a.playing:
+ pass
+ print("stopped")"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the AudioOut and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> AudioOut:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def play(self, sample: _typing.AudioSample, *, loop: bool = False) -> None:
+ """Plays the sample once when loop=False and continuously when loop=True.
+ Does not block. Use `playing` to block.
+
+ Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+
+ The sample itself should consist of 16 bit samples. Microcontrollers with a lower output
+ resolution will use the highest order bits to output. For example, the SAMD21 has a 10 bit
+ DAC that ignores the lowest 6 bits when playing 16 bit samples."""
+ ...
+ def stop(self) -> None:
+ """Stops playback and resets to the start of the sample."""
+ ...
+ playing: bool
+ """True when an audio sample is being output even if `paused`. (read-only)"""
+ def pause(self) -> None:
+ """Stops playback temporarily while remembering the position. Use `resume` to resume playback."""
+ ...
+ def resume(self) -> None:
+ """Resumes sample playback after :py:func:`pause`."""
+ ...
+ paused: bool
+ """True when playback is paused. (read-only)"""
diff --git a/stubs/audiomixer/__init__.pyi b/stubs/audiomixer/__init__.pyi
new file mode 100644
index 0000000..b05b713
--- /dev/null
+++ b/stubs/audiomixer/__init__.pyi
@@ -0,0 +1,116 @@
+"""Support for audio mixing"""
+
+from __future__ import annotations
+
+from typing import Tuple
+
+import _typing
+
+class Mixer:
+ """Mixes one or more audio samples together into one sample."""
+
+ def __init__(
+ self,
+ voice_count: int = 2,
+ buffer_size: int = 1024,
+ channel_count: int = 2,
+ bits_per_sample: int = 16,
+ samples_signed: bool = True,
+ sample_rate: int = 8000,
+ ) -> None:
+ """Create a Mixer object that can mix multiple channels with the same sample rate.
+ Samples are accessed and controlled with the mixer's `audiomixer.MixerVoice` objects.
+
+ :param int voice_count: The maximum number of voices to mix
+ :param int buffer_size: The total size in bytes of the buffers to mix into
+ :param int channel_count: The number of channels the source samples contain. 1 = mono; 2 = stereo.
+ :param int bits_per_sample: The bits per sample of the samples being played
+ :param bool samples_signed: Samples are signed (True) or unsigned (False)
+ :param int sample_rate: The sample rate to be used for all samples
+
+ Playing a wave file from flash::
+
+ import board
+ import audioio
+ import audiocore
+ import audiomixer
+ import digitalio
+
+ a = audioio.AudioOut(board.A0)
+ music = audiocore.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb"))
+ drum = audiocore.WaveFile(open("drum.wav", "rb"))
+ mixer = audiomixer.Mixer(voice_count=2, sample_rate=16000, channel_count=1,
+ bits_per_sample=16, samples_signed=True)
+
+ print("playing")
+ # Have AudioOut play our Mixer source
+ a.play(mixer)
+ # Play the first sample voice
+ mixer.voice[0].play(music)
+ while mixer.playing:
+ # Play the second sample voice
+ mixer.voice[1].play(drum)
+ time.sleep(1)
+ print("stopped")"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the Mixer and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> Mixer:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ playing: bool
+ """True when any voice is being output. (read-only)"""
+
+ sample_rate: int
+ """32 bit value that dictates how quickly samples are played in Hertz (cycles per second)."""
+
+ voice: Tuple[MixerVoice, ...]
+ """A tuple of the mixer's `audiomixer.MixerVoice` object(s).
+
+ .. code-block:: python
+
+ >>> mixer.voice
+ (,)"""
+ def play(
+ self, sample: _typing.AudioSample, *, voice: int = 0, loop: bool = False
+ ) -> None:
+ """Plays the sample once when loop=False and continuously when loop=True.
+ Does not block. Use `playing` to block.
+
+ Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+
+ The sample must match the Mixer's encoding settings given in the constructor."""
+ ...
+ def stop_voice(self, voice: int = 0) -> None:
+ """Stops playback of the sample on the given voice."""
+ ...
+
+class MixerVoice:
+ """Voice objects used with Mixer
+
+ Used to access and control samples with `audiomixer.Mixer`."""
+
+ def __init__(self) -> None:
+ """MixerVoice instance object(s) created by `audiomixer.Mixer`."""
+ ...
+ def play(self, sample: _typing.AudioSample, *, loop: bool = False) -> None:
+ """Plays the sample once when ``loop=False``, and continuously when ``loop=True``.
+ Does not block. Use `playing` to block.
+
+ Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+
+ The sample must match the `audiomixer.Mixer`'s encoding settings given in the constructor."""
+ ...
+ def stop(self) -> None:
+ """Stops playback of the sample on this voice."""
+ ...
+ level: float
+ """The volume level of a voice, as a floating point number between 0 and 1."""
+
+ playing: bool
+ """True when this voice is being output. (read-only)"""
diff --git a/stubs/audiomp3/__init__.pyi b/stubs/audiomp3/__init__.pyi
new file mode 100644
index 0000000..e7f7754
--- /dev/null
+++ b/stubs/audiomp3/__init__.pyi
@@ -0,0 +1,66 @@
+"""Support for MP3-compressed audio files"""
+
+from __future__ import annotations
+
+import typing
+
+from _typing import WriteableBuffer
+
+class MP3Decoder:
+ """Load a mp3 file for audio playback"""
+
+ def __init__(self, file: typing.BinaryIO, buffer: WriteableBuffer) -> None:
+
+ """Load a .mp3 file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`.
+
+ :param typing.BinaryIO file: Already opened mp3 file
+ :param ~_typing.WriteableBuffer buffer: Optional pre-allocated buffer, that will be split in half and used for double-buffering of the data. If not provided, two buffers are allocated internally. The specific buffer size required depends on the mp3 file.
+
+
+ Playing a mp3 file from flash::
+
+ import board
+ import audiomp3
+ import audioio
+ import digitalio
+
+ # Required for CircuitPlayground Express
+ speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
+ speaker_enable.switch_to_output(value=True)
+
+ data = open("cplay-16bit-16khz-64kbps.mp3", "rb")
+ mp3 = audiomp3.MP3Decoder(data)
+ a = audioio.AudioOut(board.A0)
+
+ print("playing")
+ a.play(mp3)
+ while a.playing:
+ pass
+ print("stopped")"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the MP3 and releases all memory resources for reuse."""
+ ...
+ def __enter__(self) -> MP3Decoder:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ file: typing.BinaryIO
+ """File to play back."""
+
+ sample_rate: int
+ """32 bit value that dictates how quickly samples are loaded into the DAC
+ in Hertz (cycles per second). When the sample is looped, this can change
+ the pitch output without changing the underlying sample."""
+
+ bits_per_sample: int
+ """Bits per sample. (read only)"""
+
+ channel_count: int
+ """Number of audio channels. (read only)"""
+
+ rms_level: float
+ """The RMS audio level of a recently played moment of audio. (read only)"""
diff --git a/stubs/audiopwmio/__init__.pyi b/stubs/audiopwmio/__init__.pyi
new file mode 100644
index 0000000..a88e764
--- /dev/null
+++ b/stubs/audiopwmio/__init__.pyi
@@ -0,0 +1,114 @@
+"""Audio output via digital PWM
+
+The `audiopwmio` module contains classes to provide access to audio IO.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+Since CircuitPython 5, `Mixer`, `RawSample` and `WaveFile` are moved
+to :mod:`audiocore`."""
+
+from __future__ import annotations
+
+from typing import Optional
+
+import _typing
+import microcontroller
+
+class PWMAudioOut:
+ """Output an analog audio signal by varying the PWM duty cycle."""
+
+ def __init__(
+ self,
+ left_channel: microcontroller.Pin,
+ *,
+ right_channel: Optional[microcontroller.Pin] = None,
+ quiescent_value: int = 0x8000
+ ) -> None:
+ """Create a PWMAudioOut object associated with the given pin(s). This allows you to
+ play audio signals out on the given pin(s). In contrast to mod:`audioio`,
+ the pin(s) specified are digital pins, and are driven with a device-dependent PWM
+ signal.
+
+ :param ~microcontroller.Pin left_channel: The pin to output the left channel to
+ :param ~microcontroller.Pin right_channel: The pin to output the right channel to
+ :param int quiescent_value: The output value when no signal is present. Samples should start
+ and end with this value to prevent audible popping.
+
+ Simple 8ksps 440 Hz sin wave::
+
+ import audiocore
+ import audiopwmio
+ import board
+ import array
+ import time
+ import math
+
+ # Generate one period of sine wav.
+ length = 8000 // 440
+ sine_wave = array.array("H", [0] * length)
+ for i in range(length):
+ sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15)
+
+ dac = audiopwmio.PWMAudioOut(board.SPEAKER)
+ sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000)
+ dac.play(sine_wave, loop=True)
+ time.sleep(1)
+ dac.stop()
+
+ Playing a wave file from flash::
+
+ import board
+ import audiocore
+ import audiopwmio
+ import digitalio
+
+ # Required for CircuitPlayground Express
+ speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
+ speaker_enable.switch_to_output(value=True)
+
+ data = open("cplay-5.1-16bit-16khz.wav", "rb")
+ wav = audiocore.WaveFile(data)
+ a = audiopwmio.PWMAudioOut(board.SPEAKER)
+
+ print("playing")
+ a.play(wav)
+ while a.playing:
+ pass
+ print("stopped")"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the PWMAudioOut and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> PWMAudioOut:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def play(self, sample: _typing.AudioSample, *, loop: bool = False) -> None:
+ """Plays the sample once when loop=False and continuously when loop=True.
+ Does not block. Use `playing` to block.
+
+ Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+
+ The sample itself should consist of 16 bit samples. Microcontrollers with a lower output
+ resolution will use the highest order bits to output. For example, the SAMD21 has a 10 bit
+ DAC that ignores the lowest 6 bits when playing 16 bit samples."""
+ ...
+ def stop(self) -> None:
+ """Stops playback and resets to the start of the sample."""
+ ...
+ playing: bool
+ """True when an audio sample is being output even if `paused`. (read-only)"""
+ def pause(self) -> None:
+ """Stops playback temporarily while remembering the position. Use `resume` to resume playback."""
+ ...
+ def resume(self) -> None:
+ """Resumes sample playback after :py:func:`pause`."""
+ ...
+ paused: bool
+ """True when playback is paused. (read-only)"""
diff --git a/stubs/bitbangio/__init__.pyi b/stubs/bitbangio/__init__.pyi
new file mode 100644
index 0000000..915ebbe
--- /dev/null
+++ b/stubs/bitbangio/__init__.pyi
@@ -0,0 +1,306 @@
+"""Digital protocols implemented by the CPU
+
+The `bitbangio` module contains classes to provide digital bus protocol
+support regardless of whether the underlying hardware exists to use the
+protocol.
+
+First try to use `busio` module instead which may utilize peripheral
+hardware to implement the protocols. Native implementations will be faster
+than bitbanged versions and have more capabilities.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+For example::
+
+ import bitbangio
+ from board import *
+
+ i2c = bitbangio.I2C(SCL, SDA)
+ print(i2c.scan())
+ i2c.deinit()
+
+This example will initialize the the device, run
+:py:meth:`~bitbangio.I2C.scan` and then :py:meth:`~bitbangio.I2C.deinit` the
+hardware. The last step is optional because CircuitPython automatically
+resets hardware after a program finishes."""
+
+from __future__ import annotations
+
+from typing import List, Optional
+
+import microcontroller
+from _typing import ReadableBuffer, WriteableBuffer
+
+class I2C:
+ """Two wire serial protocol"""
+
+ def __init__(
+ self,
+ scl: microcontroller.Pin,
+ sda: microcontroller.Pin,
+ *,
+ frequency: int = 400000,
+ timeout: int = 255
+ ) -> None:
+ """I2C is a two-wire protocol for communicating between devices. At the
+ physical level it consists of 2 wires: SCL and SDA, the clock and data
+ lines respectively.
+
+ .. seealso:: Using this class directly requires careful lock management.
+ Instead, use :class:`~adafruit_bus_device.i2c_device.I2CDevice` to
+ manage locks.
+
+ .. seealso:: Using this class to directly read registers requires manual
+ bit unpacking. Instead, use an existing driver or make one with
+ :ref:`Register ` data descriptors.
+
+ :param ~microcontroller.Pin scl: The clock pin
+ :param ~microcontroller.Pin sda: The data pin
+ :param int frequency: The clock frequency of the bus
+ :param int timeout: The maximum clock stretching timeout in microseconds"""
+ ...
+ def deinit(self) -> None:
+ """Releases control of the underlying hardware so other classes can use it."""
+ ...
+ def __enter__(self) -> I2C:
+ """No-op used in Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware on context exit. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def scan(self) -> List[int]:
+ """Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of
+ those that respond. A device responds if it pulls the SDA line low after
+ its address (including a read bit) is sent on the bus."""
+ ...
+ def try_lock(self) -> bool:
+ """Attempts to grab the I2C lock. Returns True on success."""
+ ...
+ def unlock(self) -> None:
+ """Releases the I2C lock."""
+ ...
+ def readfrom_into(
+ self,
+ address: int,
+ buffer: WriteableBuffer,
+ *,
+ start: int = 0,
+ end: Optional[int] = None
+ ) -> None:
+ """Read into ``buffer`` from the device selected by ``address``.
+ The number of bytes read will be the length of ``buffer``.
+ At least one byte must be read.
+
+ If ``start`` or ``end`` is provided, then the buffer will be sliced
+ as if ``buffer[start:end]``. This will not cause an allocation like
+ ``buf[start:end]`` will so it saves memory.
+
+ :param int address: 7-bit device address
+ :param ~_typing.WriteableBuffer buffer: buffer to write into
+ :param int start: Index to start writing at
+ :param int end: Index to write up to but not include"""
+ ...
+ def writeto(
+ self,
+ address: int,
+ buffer: ReadableBuffer,
+ *,
+ start: int = 0,
+ end: Optional[int] = None,
+ stop: bool = True
+ ) -> None:
+ """Write the bytes from ``buffer`` to the device selected by ``address`` and then transmits a
+ stop bit. Use `writeto_then_readfrom` when needing a write, no stop and repeated start
+ before a read.
+
+ If ``start`` or ``end`` is provided, then the buffer will be sliced
+ as if ``buffer[start:end]``. This will not cause an allocation like
+ ``buffer[start:end]`` will so it saves memory.
+
+ Writing a buffer or slice of length zero is permitted, as it can be used
+ to poll for the existence of a device.
+
+ :param int address: 7-bit device address
+ :param ~_typing.ReadableBuffer buffer: buffer containing the bytes to write
+ :param int start: Index to start writing from
+ :param int end: Index to read up to but not include"""
+ ...
+ def writeto_then_readfrom(
+ self,
+ address: int,
+ out_buffer: ReadableBuffer,
+ in_buffer: ReadableBuffer,
+ *,
+ out_start: int = 0,
+ out_end: Optional[int] = None,
+ in_start: int = 0,
+ in_end: Optional[int] = None
+ ) -> None:
+ """Write the bytes from ``out_buffer`` to the device selected by ``address``, generate no stop
+ bit, generate a repeated start and read into ``in_buffer``. ``out_buffer`` and
+ ``in_buffer`` can be the same buffer because they are used sequentially.
+
+ If ``start`` or ``end`` is provided, then the corresponding buffer will be sliced
+ as if ``buffer[start:end]``. This will not cause an allocation like ``buf[start:end]``
+ will so it saves memory.
+
+ :param int address: 7-bit device address
+ :param ~_typing.ReadableBuffer out_buffer: buffer containing the bytes to write
+ :param ~_typing.WriteableBuffer in_buffer: buffer to write into
+ :param int out_start: Index to start writing from
+ :param int out_end: Index to read up to but not include. Defaults to ``len(buffer)``
+ :param int in_start: Index to start writing at
+ :param int in_end: Index to write up to but not include. Defaults to ``len(buffer)``"""
+
+class OneWire:
+ """Lowest-level of the Maxim OneWire protocol
+
+ :class:`~bitbangio.OneWire` implements the timing-sensitive foundation of
+ the Maxim (formerly Dallas Semi) OneWire protocol.
+
+ Protocol definition is here: https://www.maximintegrated.com/en/app-notes/index.mvp/id/126"""
+
+ def __init__(self, pin: microcontroller.Pin) -> None:
+
+ """Create a OneWire object associated with the given pin. The object
+ implements the lowest level timing-sensitive bits of the protocol.
+
+ :param ~microcontroller.Pin pin: Pin to read pulses from.
+
+ Read a short series of pulses::
+
+ import bitbangio
+ import board
+
+ onewire = bitbangio.OneWire(board.D7)
+ onewire.reset()
+ onewire.write_bit(True)
+ onewire.write_bit(False)
+ print(onewire.read_bit())"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialize the OneWire bus and release any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> OneWire:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def reset(self) -> bool:
+ """Reset the OneWire bus"""
+ ...
+ def read_bit(self) -> bool:
+ """Read in a bit
+
+ :returns: bit state read
+ :rtype: bool"""
+ ...
+ def write_bit(self, value: bool) -> None:
+ """Write out a bit based on value."""
+ ...
+
+class SPI:
+ """A 3-4 wire serial protocol
+
+ SPI is a serial protocol that has exclusive pins for data in and out of the
+ main device. It is typically faster than :py:class:`~bitbangio.I2C` because a
+ separate pin is used to select a device rather than a transmitted
+ address. This class only manages three of the four SPI lines: `!clock`,
+ `!MOSI`, `!MISO`. Its up to the client to manage the appropriate
+ select line, often abbreviated `!CS` or `!SS`. (This is common because
+ multiple secondaries can share the `!clock`, `!MOSI` and `!MISO` lines
+ and therefore the hardware.)"""
+
+ def __init__(
+ self,
+ clock: microcontroller.Pin,
+ MOSI: Optional[microcontroller.Pin] = None,
+ MISO: Optional[microcontroller.Pin] = None,
+ ) -> None:
+ """Construct an SPI object on the given pins.
+
+ .. seealso:: Using this class directly requires careful lock management.
+ Instead, use :class:`~adafruit_bus_device.spi_device.SPIDevice` to
+ manage locks.
+
+ .. seealso:: Using this class to directly read registers requires manual
+ bit unpacking. Instead, use an existing driver or make one with
+ :ref:`Register ` data descriptors.
+
+
+ :param ~microcontroller.Pin clock: the pin to use for the clock.
+ :param ~microcontroller.Pin MOSI: the Main Out Selected In pin.
+ :param ~microcontroller.Pin MISO: the Main In Selected Out pin."""
+ ...
+ def deinit(self) -> None:
+ """Turn off the SPI bus."""
+ ...
+ def __enter__(self) -> SPI:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def configure(
+ self,
+ *,
+ baudrate: int = 100000,
+ polarity: int = 0,
+ phase: int = 0,
+ bits: int = 8
+ ) -> None:
+ """Configures the SPI bus. Only valid when locked.
+
+ :param int baudrate: the clock rate in Hertz
+ :param int polarity: the base state of the clock line (0 or 1)
+ :param int phase: the edge of the clock that data is captured. First (0)
+ or second (1). Rising or falling depends on clock polarity.
+ :param int bits: the number of bits per word"""
+ ...
+ def try_lock(self) -> bool:
+ """Attempts to grab the SPI lock. Returns True on success.
+
+ :return: True when lock has been grabbed
+ :rtype: bool"""
+ ...
+ def unlock(self) -> None:
+ """Releases the SPI lock."""
+ ...
+ def write(self, buf: ReadableBuffer) -> None:
+ """Write the data contained in ``buf``. Requires the SPI being locked.
+ If the buffer is empty, nothing happens."""
+ ...
+ def readinto(self, buf: WriteableBuffer) -> None:
+ """Read into the buffer specified by ``buf`` while writing zeroes.
+ Requires the SPI being locked.
+ If the number of bytes to read is 0, nothing happens."""
+ ...
+ def write_readinto(
+ self,
+ buffer_out: ReadableBuffer,
+ buffer_in: WriteableBuffer,
+ *,
+ out_start: int = 0,
+ out_end: Optional[int] = None,
+ in_start: int = 0,
+ in_end: Optional[int] = None
+ ) -> None:
+ """Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``.
+ The lengths of the slices defined by ``buffer_out[out_start:out_end]`` and ``buffer_in[in_start:in_end]``
+ must be equal.
+ If buffer slice lengths are both 0, nothing happens.
+
+ :param ~_typing.ReadableBuffer buffer_out: Write out the data in this buffer
+ :param ~_typing.WriteableBuffer buffer_in: Read data into this buffer
+ :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]``
+ :param int out_end: End of the slice; this index is not included. Defaults to ``len(buffer_out)``
+ :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]``
+ :param int in_end: End of the slice; this index is not included. Defaults to ``len(buffer_in)``"""
+ ...
diff --git a/stubs/board/__init__.pyi b/stubs/board/__init__.pyi
new file mode 100644
index 0000000..fe6ee35
--- /dev/null
+++ b/stubs/board/__init__.pyi
@@ -0,0 +1,29 @@
+"""Board specific pin names
+
+Common container for board base pin names. These will vary from board to
+board so don't expect portability when using this module.
+
+.. warning:: The board module varies by board. The APIs documented here may or may not be
+ available on a specific board."""
+
+from __future__ import annotations
+
+import busio
+
+def I2C() -> busio.I2C:
+ """Returns the `busio.I2C` object for the board designated SDA and SCL pins. It is a singleton."""
+ ...
+
+def SPI() -> busio.SPI:
+ """Returns the `busio.SPI` object for the board designated SCK, MOSI and MISO pins. It is a
+ singleton."""
+ ...
+
+def UART() -> busio.UART:
+ """Returns the `busio.UART` object for the board designated TX and RX pins. It is a singleton.
+
+ The object created uses the default parameter values for `busio.UART`. If you need to set
+ parameters that are not changeable after creation, such as ``receiver_buffer_size``,
+ do not use `board.UART()`; instead create a `busio.UART` object explicitly with the
+ desired parameters."""
+ ...
diff --git a/stubs/busio/__init__.pyi b/stubs/busio/__init__.pyi
new file mode 100644
index 0000000..a03f3b6
--- /dev/null
+++ b/stubs/busio/__init__.pyi
@@ -0,0 +1,461 @@
+"""Hardware accelerated external bus access
+
+The `busio` module contains classes to support a variety of serial
+protocols.
+
+When the microcontroller does not support the behavior in a hardware
+accelerated fashion it may internally use a bitbang routine. However, if
+hardware support is available on a subset of pins but not those provided,
+then a RuntimeError will be raised. Use the `bitbangio` module to explicitly
+bitbang a serial protocol on any general purpose pins.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+For example::
+
+ import busio
+ from board import *
+
+ i2c = busio.I2C(SCL, SDA)
+ print(i2c.scan())
+ i2c.deinit()
+
+This example will initialize the the device, run
+:py:meth:`~busio.I2C.scan` and then :py:meth:`~busio.I2C.deinit` the
+hardware. The last step is optional because CircuitPython automatically
+resets hardware after a program finishes."""
+
+from __future__ import annotations
+
+from typing import List, Optional
+
+import microcontroller
+from _typing import ReadableBuffer, WriteableBuffer
+
+class I2C:
+ """Two wire serial protocol"""
+
+ def __init__(
+ self,
+ scl: microcontroller.Pin,
+ sda: microcontroller.Pin,
+ *,
+ frequency: int = 100000,
+ timeout: int = 255
+ ) -> None:
+
+ """I2C is a two-wire protocol for communicating between devices. At the
+ physical level it consists of 2 wires: SCL and SDA, the clock and data
+ lines respectively.
+
+ .. seealso:: Using this class directly requires careful lock management.
+ Instead, use :class:`~adafruit_bus_device.i2c_device.I2CDevice` to
+ manage locks.
+
+ .. seealso:: Using this class to directly read registers requires manual
+ bit unpacking. Instead, use an existing driver or make one with
+ :ref:`Register ` data descriptors.
+
+ :param ~microcontroller.Pin scl: The clock pin
+ :param ~microcontroller.Pin sda: The data pin
+ :param int frequency: The clock frequency in Hertz
+ :param int timeout: The maximum clock stretching timeut - (used only for bitbangio.I2C; ignored for busio.I2C)
+
+ .. note:: On the nRF52840, only one I2C object may be created,
+ except on the Circuit Playground Bluefruit, which allows two,
+ one for the onboard accelerometer, and one for offboard use."""
+ ...
+ def deinit(self) -> None:
+ """Releases control of the underlying hardware so other classes can use it."""
+ ...
+ def __enter__(self) -> I2C:
+ """No-op used in Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware on context exit. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def scan(self) -> List[int]:
+ """Scan all I2C addresses between 0x08 and 0x77 inclusive and return a
+ list of those that respond.
+
+ :return: List of device ids on the I2C bus
+ :rtype: list"""
+ ...
+ def try_lock(self) -> bool:
+ """Attempts to grab the I2C lock. Returns True on success.
+
+ :return: True when lock has been grabbed
+ :rtype: bool"""
+ ...
+ def unlock(self) -> None:
+ """Releases the I2C lock."""
+ ...
+ def readfrom_into(
+ self,
+ address: int,
+ buffer: WriteableBuffer,
+ *,
+ start: int = 0,
+ end: Optional[int] = None
+ ) -> None:
+ """Read into ``buffer`` from the device selected by ``address``.
+ The number of bytes read will be the length of ``buffer``.
+ At least one byte must be read.
+
+ If ``start`` or ``end`` is provided, then the buffer will be sliced
+ as if ``buffer[start:end]``. This will not cause an allocation like
+ ``buf[start:end]`` will so it saves memory.
+
+ :param int address: 7-bit device address
+ :param ~_typing.WriteableBuffer buffer: buffer to write into
+ :param int start: Index to start writing at
+ :param int end: Index to write up to but not include. Defaults to ``len(buffer)``"""
+ ...
+ def writeto(
+ self,
+ address: int,
+ buffer: ReadableBuffer,
+ *,
+ start: int = 0,
+ end: Optional[int] = None,
+ stop: bool = True
+ ) -> None:
+ """Write the bytes from ``buffer`` to the device selected by ``address`` and
+ then transmit a stop bit.
+
+ If ``start`` or ``end`` is provided, then the buffer will be sliced
+ as if ``buffer[start:end]``. This will not cause an allocation like
+ ``buffer[start:end]`` will so it saves memory.
+
+ Writing a buffer or slice of length zero is permitted, as it can be used
+ to poll for the existence of a device.
+
+ :param int address: 7-bit device address
+ :param ~_typing.ReadbleBuffer buffer: buffer containing the bytes to write
+ :param int start: Index to start writing from
+ :param int end: Index to read up to but not include. Defaults to ``len(buffer)``"""
+ ...
+ def writeto_then_readfrom(
+ self,
+ address: int,
+ out_buffer: ReadableBuffer,
+ in_buffer: WriteableBuffer,
+ *,
+ out_start: int = 0,
+ out_end: Optional[int] = None,
+ in_start: int = 0,
+ in_end: Optional[int] = None
+ ) -> None:
+ """Write the bytes from ``out_buffer`` to the device selected by ``address``, generate no stop
+ bit, generate a repeated start and read into ``in_buffer``. ``out_buffer`` and
+ ``in_buffer`` can be the same buffer because they are used sequentially.
+
+ if ``start`` or ``end`` is provided, then the corresponding buffer will be sliced
+ as if ``buffer[start:end]``. This will not cause an allocation like ``buf[start:end]``
+ will so it saves memory.
+
+ :param int address: 7-bit device address
+ :param ~_typing.ReadbleBuffer out_buffer: buffer containing the bytes to write
+ :param ~_typing.WriteableBuffer in_buffer: buffer to write into
+ :param int out_start: Index to start writing from
+ :param int out_end: Index to read up to but not include. Defaults to ``len(buffer)``
+ :param int in_start: Index to start writing at
+ :param int in_end: Index to write up to but not include. Defaults to ``len(buffer)``"""
+ ...
+
+class OneWire:
+ """Lowest-level of the Maxim OneWire protocol"""
+
+ def __init__(self, pin: microcontroller.Pin) -> None:
+ """(formerly Dallas Semi) OneWire protocol.
+
+ Protocol definition is here: https://www.maximintegrated.com/en/app-notes/index.mvp/id/126
+
+ .. class:: OneWire(pin)
+
+ Create a OneWire object associated with the given pin. The object
+ implements the lowest level timing-sensitive bits of the protocol.
+
+ :param ~microcontroller.Pin pin: Pin connected to the OneWire bus
+
+ Read a short series of pulses::
+
+ import busio
+ import board
+
+ onewire = busio.OneWire(board.D7)
+ onewire.reset()
+ onewire.write_bit(True)
+ onewire.write_bit(False)
+ print(onewire.read_bit())"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialize the OneWire bus and release any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> OneWire:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def reset(self) -> bool:
+ """Reset the OneWire bus and read presence
+
+ :returns: False when at least one device is present
+ :rtype: bool"""
+ ...
+ def read_bit(self) -> bool:
+ """Read in a bit
+
+ :returns: bit state read
+ :rtype: bool"""
+ ...
+ def write_bit(self, value: bool) -> None:
+ """Write out a bit based on value."""
+ ...
+
+class SPI:
+ """A 3-4 wire serial protocol
+
+ SPI is a serial protocol that has exclusive pins for data in and out of the
+ main device. It is typically faster than :py:class:`~bitbangio.I2C` because a
+ separate pin is used to select a device rather than a transmitted
+ address. This class only manages three of the four SPI lines: `!clock`,
+ `!MOSI`, `!MISO`. Its up to the client to manage the appropriate
+ select line, often abbreviated `!CS` or `!SS`. (This is common because
+ multiple secondaries can share the `!clock`, `!MOSI` and `!MISO` lines
+ and therefore the hardware.)"""
+
+ def __init__(
+ self,
+ clock: microcontroller.Pin,
+ MOSI: Optional[microcontroller.Pin] = None,
+ MISO: Optional[microcontroller.Pin] = None,
+ ) -> None:
+
+ """Construct an SPI object on the given pins.
+
+ ..note:: The SPI peripherals allocated in order of desirability, if possible,
+ such as highest speed and not shared use first. For instance, on the nRF52840,
+ there is a single 32MHz SPI peripheral, and multiple 8MHz peripherals,
+ some of which may also be used for I2C. The 32MHz SPI peripheral is returned
+ first, then the exclusive 8MHz SPI peripheral, and finally the shared 8MHz
+ peripherals.
+
+ .. seealso:: Using this class directly requires careful lock management.
+ Instead, use :class:`~adafruit_bus_device.spi_device.SPIDevice` to
+ manage locks.
+
+ .. seealso:: Using this class to directly read registers requires manual
+ bit unpacking. Instead, use an existing driver or make one with
+ :ref:`Register ` data descriptors.
+
+ :param ~microcontroller.Pin clock: the pin to use for the clock.
+ :param ~microcontroller.Pin MOSI: the Main Out Selected In pin.
+ :param ~microcontroller.Pin MISO: the Main In Selected Out pin."""
+ ...
+ def deinit(self) -> None:
+ """Turn off the SPI bus."""
+ ...
+ def __enter__(self) -> SPI:
+ """No-op used by Context Managers.
+ Provided by context manager helper."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def configure(
+ self,
+ *,
+ baudrate: int = 100000,
+ polarity: int = 0,
+ phase: int = 0,
+ bits: int = 8
+ ) -> None:
+ """Configures the SPI bus. The SPI object must be locked.
+
+ :param int baudrate: the desired clock rate in Hertz. The actual clock rate may be higher or lower
+ due to the granularity of available clock settings.
+ Check the `frequency` attribute for the actual clock rate.
+ :param int polarity: the base state of the clock line (0 or 1)
+ :param int phase: the edge of the clock that data is captured. First (0)
+ or second (1). Rising or falling depends on clock polarity.
+ :param int bits: the number of bits per word
+
+ .. note:: On the SAMD21, it is possible to set the baudrate to 24 MHz, but that
+ speed is not guaranteed to work. 12 MHz is the next available lower speed, and is
+ within spec for the SAMD21.
+
+ .. note:: On the nRF52840, these baudrates are available: 125kHz, 250kHz, 1MHz, 2MHz, 4MHz,
+ and 8MHz.
+ If you pick a a baudrate other than one of these, the nearest lower
+ baudrate will be chosen, with a minimum of 125kHz.
+ Two SPI objects may be created, except on the Circuit Playground Bluefruit,
+ which allows only one (to allow for an additional I2C object)."""
+ ...
+ def try_lock(self) -> bool:
+ """Attempts to grab the SPI lock. Returns True on success.
+
+ :return: True when lock has been grabbed
+ :rtype: bool"""
+ ...
+ def unlock(self) -> None:
+ """Releases the SPI lock."""
+ ...
+ def write(
+ self, buffer: ReadableBuffer, *, start: int = 0, end: Optional[int] = None
+ ) -> None:
+ """Write the data contained in ``buffer``. The SPI object must be locked.
+ If the buffer is empty, nothing happens.
+
+ :param ~_typing.ReadableBuffer buffer: Write out the data in this buffer
+ :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]``
+ :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)``"""
+ ...
+ def readinto(
+ self,
+ buffer: WriteableBuffer,
+ *,
+ start: int = 0,
+ end: Optional[int] = None,
+ write_value: int = 0
+ ) -> None:
+ """Read into ``buffer`` while writing ``write_value`` for each byte read.
+ The SPI object must be locked.
+ If the number of bytes to read is 0, nothing happens.
+
+ :param ~_typing.WriteableBuffer buffer: Read data into this buffer
+ :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]``
+ :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)``
+ :param int write_value: Value to write while reading. (Usually ignored.)"""
+ ...
+ def write_readinto(
+ self,
+ buffer_out: ReadableBuffer,
+ buffer_in: WriteableBuffer,
+ *,
+ out_start: int = 0,
+ out_end: Optional[int] = None,
+ in_start: int = 0,
+ in_end: Optional[int] = None
+ ) -> None:
+ """Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``.
+ The SPI object must be locked.
+ The lengths of the slices defined by ``buffer_out[out_start:out_end]`` and ``buffer_in[in_start:in_end]``
+ must be equal.
+ If buffer slice lengths are both 0, nothing happens.
+
+ :param ~_typing.ReadableBuffer buffer_out: Write out the data in this buffer
+ :param ~_typing.WriteableBuffer buffer_in: Read data into this buffer
+ :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]``
+ :param int out_end: End of the slice; this index is not included. Defaults to ``len(buffer_out)``
+ :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]``
+ :param int in_end: End of the slice; this index is not included. Defaults to ``len(buffer_in)``"""
+ ...
+ frequency: int
+ """The actual SPI bus frequency. This may not match the frequency requested
+ due to internal limitations."""
+
+class UART:
+ """A bidirectional serial protocol"""
+
+ def __init__(
+ self,
+ tx: microcontroller.Pin,
+ rx: microcontroller.Pin,
+ *,
+ baudrate: int = 9600,
+ bits: int = 8,
+ parity: Optional[Parity] = None,
+ stop: int = 1,
+ timeout: float = 1,
+ receiver_buffer_size: int = 64
+ ) -> None:
+ """A common bidirectional serial protocol that uses an an agreed upon speed
+ rather than a shared clock line.
+
+ :param ~microcontroller.Pin tx: the pin to transmit with, or ``None`` if this ``UART`` is receive-only.
+ :param ~microcontroller.Pin rx: the pin to receive on, or ``None`` if this ``UART`` is transmit-only.
+ :param ~microcontroller.Pin rts: the pin for rts, or ``None`` if rts not in use.
+ :param ~microcontroller.Pin cts: the pin for cts, or ``None`` if cts not in use.
+ :param ~microcontroller.Pin rs485_dir: the output pin for rs485 direction setting, or ``None`` if rs485 not in use.
+ :param bool rs485_invert: rs485_dir pin active high when set. Active low otherwise.
+ :param int baudrate: the transmit and receive speed.
+ :param int bits: the number of bits per byte, 7, 8 or 9.
+ :param Parity parity: the parity used for error checking.
+ :param int stop: the number of stop bits, 1 or 2.
+ :param float timeout: the timeout in seconds to wait for the first character and between subsequent characters when reading. Raises ``ValueError`` if timeout >100 seconds.
+ :param int receiver_buffer_size: the character length of the read buffer (0 to disable). (When a character is 9 bits the buffer will be 2 * receiver_buffer_size bytes.)
+
+ *New in CircuitPython 4.0:* ``timeout`` has incompatibly changed units from milliseconds to seconds.
+ The new upper limit on ``timeout`` is meant to catch mistaken use of milliseconds."""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the UART and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> UART:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def read(self, nbytes: Optional[int] = None) -> Optional[bytes]:
+ """Read characters. If ``nbytes`` is specified then read at most that many
+ bytes. Otherwise, read everything that arrives until the connection
+ times out. Providing the number of bytes expected is highly recommended
+ because it will be faster.
+
+ :return: Data read
+ :rtype: bytes or None"""
+ ...
+ def readinto(self, buf: WriteableBuffer) -> Optional[int]:
+ """Read bytes into the ``buf``. Read at most ``len(buf)`` bytes.
+
+ :return: number of bytes read and stored into ``buf``
+ :rtype: int or None (on a non-blocking error)
+
+ *New in CircuitPython 4.0:* No length parameter is permitted."""
+ ...
+ def readline(self) -> bytes:
+ """Read a line, ending in a newline character, or
+ return None if a timeout occurs sooner, or
+ return everything readable if no newline is found and timeout=0
+
+ :return: the line read
+ :rtype: bytes or None"""
+ ...
+ def write(self, buf: WriteableBuffer) -> Optional[int]:
+ """Write the buffer of bytes to the bus.
+
+ *New in CircuitPython 4.0:* ``buf`` must be bytes, not a string.
+
+ :return: the number of bytes written
+ :rtype: int or None"""
+ ...
+ baudrate: int
+ """The current baudrate."""
+
+ in_waiting: int
+ """The number of bytes in the input buffer, available to be read"""
+
+ timeout: float
+ """The current timeout, in seconds (float)."""
+ def reset_input_buffer(self) -> None:
+ """Discard any unread characters in the input buffer."""
+ ...
+
+class Parity:
+ """Enum-like class to define the parity used to verify correct data transfer."""
+
+ ODD: int
+ """Total number of ones should be odd."""
+
+ EVEN: int
+ """Total number of ones should be even."""
diff --git a/stubs/camera/__init__.pyi b/stubs/camera/__init__.pyi
new file mode 100644
index 0000000..d65949e
--- /dev/null
+++ b/stubs/camera/__init__.pyi
@@ -0,0 +1,58 @@
+"""Support for camera input
+
+The `camera` module contains classes to control the camera and take pictures."""
+
+from __future__ import annotations
+
+from _typing import WriteableBuffer
+
+class Camera:
+ """The class to control camera.
+
+ Usage::
+
+ import board
+ import sdioio
+ import storage
+ import camera
+
+ sd = sdioio.SDCard(
+ clock=board.SDIO_CLOCK,
+ command=board.SDIO_COMMAND,
+ data=board.SDIO_DATA,
+ frequency=25000000)
+ vfs = storage.VfsFat(sd)
+ storage.mount(vfs, '/sd')
+
+ cam = camera.Camera()
+
+ buffer = bytearray(512 * 1024)
+ file = open("/sd/image.jpg","wb")
+ size = cam.take_picture(buffer, width=1920, height=1080, format=camera.ImageFormat.JPG)
+ file.write(buffer, size)
+ file.close()"""
+
+ def __init__(self) -> None:
+ """Initialize camera."""
+ ...
+ def deinit(self) -> None:
+ """De-initialize camera."""
+ ...
+ def take_picture(self, buf: WriteableBuffer, format: ImageFormat) -> int:
+ """Take picture and save to ``buf`` in the given ``format``. The size of the picture
+ taken is ``width`` by ``height`` in pixels.
+
+ :return: the number of bytes written into buf
+ :rtype: int"""
+ ...
+
+class ImageFormat:
+ """Image format"""
+
+ def __init__(self) -> None:
+ """Enum-like class to define the image format."""
+ JPG: ImageFormat
+ """JPG format."""
+
+ RGB565: ImageFormat
+ """RGB565 format."""
diff --git a/stubs/canio/__init__.pyi b/stubs/canio/__init__.pyi
new file mode 100644
index 0000000..a798d3d
--- /dev/null
+++ b/stubs/canio/__init__.pyi
@@ -0,0 +1,277 @@
+"""CAN bus access
+
+The `canio` module contains low level classes to support the CAN bus
+protocol.
+
+CAN and Listener classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+For example::
+
+ import canio
+ from board import *
+
+ can = canio.CAN(board.CAN_RX, board.CAN_TX, baudrate=1000000)
+ message = canio.Message(id=0x0408, data=b"adafruit")
+ can.send(message)
+ can.deinit()
+
+This example will write the data 'adafruit' onto the CAN bus to any
+device listening for message id 0x0408.
+
+A CAN bus involves a transceiver, which is often a separate chip with a "standby" pin.
+If your board has a CAN_STANDBY pin, ensure to set it to an output with the value False
+to enable the transceiver.
+
+Other implementations of the CAN device may exist (for instance, attached
+via an SPI bus). If so their constructor arguments may differ, but
+otherwise we encourage implementors to follow the API that the core uses.
+"""
+
+from __future__ import annotations
+
+from types import TracebackType
+from typing import Optional, Sequence, Type, Union
+
+import microcontroller
+
+class BusState:
+ """The state of the CAN bus"""
+
+ ERROR_ACTIVE: object
+ """The bus is in the normal (active) state"""
+
+ ERROR_WARNING: object
+ """The bus is in the normal (active) state, but a moderate number of errors have occurred recently.
+
+ NOTE: Not all implementations may use ERROR_WARNING. Do not rely on seeing ERROR_WARNING before ERROR_PASSIVE."""
+
+ ERROR_PASSIVE: object
+ """The bus is in the passive state due to the number of errors that have occurred recently.
+
+ This device will acknowledge packets it receives, but cannot transmit messages.
+ If additional errors occur, this device may progress to BUS_OFF.
+ If it successfully acknowledges other packets on the bus, it can return to ERROR_WARNING or ERROR_ACTIVE and transmit packets.
+ """
+
+ BUS_OFF: object
+ """The bus has turned off due to the number of errors that have
+ occurred recently. It must be restarted before it will send or receive
+ packets. This device will neither send or acknowledge packets on the bus."""
+
+class CAN:
+ """CAN bus protocol"""
+
+ def __init__(
+ self,
+ tx: microcontroller.Pin,
+ rx: microcontroller.Pin,
+ *,
+ baudrate: int = 250000,
+ loopback: bool = False,
+ silent: bool = False,
+ auto_restart: bool = False,
+ ) -> None:
+ """A common shared-bus protocol. The rx and tx pins are generally
+ connected to a transceiver which controls the H and L pins on a
+ shared bus.
+
+ :param ~microcontroller.Pin rx: the pin to receive with
+ :param ~microcontroller.Pin tx: the pin to transmit with
+ :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value.
+ :param bool loopback: When True the ``rx`` pin's value is ignored, and the device receives the packets it sends.
+ :param bool silent: When True the ``tx`` pin is always driven to the high logic level. This mode can be used to "sniff" a CAN bus without interfering.
+ :param bool auto_restart: If True, will restart communications after entering bus-off state
+ """
+ ...
+ auto_restart: bool
+ """If True, will restart communications after entering bus-off state"""
+
+ baudrate: int
+ """The baud rate (read-only)"""
+
+ transmit_error_count: int
+ """The number of transmit errors (read-only). Increased for a detected transmission error, decreased for successful transmission. Limited to the range from 0 to 255 inclusive. Also called TEC."""
+
+ receive_error_count: int
+ """The number of receive errors (read-only). Increased for a detected reception error, decreased for successful reception. Limited to the range from 0 to 255 inclusive. Also called REC."""
+
+ state: BusState
+ """The current state of the bus. (read-only)"""
+ def restart(self) -> None:
+ """If the device is in the bus off state, restart it."""
+ ...
+ def listen(
+ self, matches: Optional[Sequence[Match]] = None, *, timeout: float = 10
+ ) -> Listener:
+ """Start receiving messages that match any one of the filters.
+
+ Creating a listener is an expensive operation and can interfere with reception of messages by other listeners.
+
+ There is an implementation-defined maximum number of listeners and limit to the complexity of the filters.
+
+ If the hardware cannot support all the requested matches, a ValueError is raised. Note that generally there are some number of hardware filters shared among all fifos.
+
+ A message can be received by at most one Listener. If more than one listener matches a message, it is undefined which one actually receives it.
+
+ An empty filter list causes all messages to be accepted.
+
+ Timeout dictates how long receive() and next() will block.
+
+ Platform specific notes:
+
+ SAM E5x supports two Listeners. Filter blocks are shared between the two
+ listeners. There are 4 standard filter blocks and 4 extended filter blocks.
+ Each block can either match 2 single addresses or a mask of addresses.
+ The number of filter blocks can be increased, up to a hardware maximum, by
+ rebuilding CircuitPython, but this decreases the CircuitPython free
+ memory even if canio is not used.
+
+ STM32F405 supports two Listeners. Filter blocks are shared between the two listeners.
+ There are 14 filter blocks. Each block can match 2 standard addresses with
+ mask or 1 extended address with mask.
+
+ ESP32S2 supports one Listener. There is a single filter block, which can either match a
+ standard address with mask or an extended address with mask.
+ """
+ ...
+ loopback: bool
+ """True if the device was created in loopback mode, False
+ otherwise (read-only)"""
+ def send(self, message: Union[RemoteTransmissionRequest, Message]) -> None:
+ """Send a message on the bus with the given data and id.
+ If the message could not be sent due to a full fifo or a bus error condition, RuntimeError is raised.
+ """
+ ...
+ silent: bool
+ """True if the device was created in silent mode, False
+ otherwise (read-only)"""
+ def deinit(self) -> None:
+ """Deinitialize this object, freeing its hardware resources"""
+ ...
+ def __enter__(self) -> CAN:
+ """Returns self, to allow the object to be used in a `with` statement for resource control"""
+ ...
+ def __exit__(
+ self,
+ unused1: Optional[Type[BaseException]],
+ unused2: Optional[BaseException],
+ unused3: Optional[TracebackType],
+ ) -> None:
+ """Calls deinit()"""
+ ...
+
+class Listener:
+ """Listens for CAN message
+
+ `canio.Listener` is not constructed directly, but instead by calling
+ `canio.CAN.listen`.
+
+ In addition to using the `receive` method to retrieve a message or
+ the `in_waiting` method to check for an available message, a
+ listener can be used as an iterable, yielding messages until no
+ message arrives within ``self.timeout`` seconds."""
+
+ def receive(self) -> Optional[Union[RemoteTransmissionRequest, Message]]:
+ """Reads a message, after waiting up to ``self.timeout`` seconds
+
+ If no message is received in time, `None` is returned. Otherwise,
+ a `Message` or `RemoteTransmissionRequest` is returned."""
+ ...
+ def in_waiting(self) -> int:
+ """Returns the number of messages (including remote
+ transmission requests) waiting"""
+ ...
+ def __iter__(self) -> Listener:
+ """Returns self
+
+ This method exists so that `Listener` can be used as an
+ iterable"""
+ ...
+ def __next__(self) -> Union[RemoteTransmissionRequest, Message]:
+ """Reads a message, after waiting up to self.timeout seconds
+
+ If no message is received in time, raises StopIteration. Otherwise,
+ a Message or is returned.
+
+ This method enables the `Listener` to be used as an
+ iterable, for instance in a for-loop."""
+ ...
+ def deinit(self) -> None:
+ """Deinitialize this object, freeing its hardware resources"""
+ ...
+ def __enter__(self) -> CAN:
+ """Returns self, to allow the object to be used in a `with` statement for resource control"""
+ ...
+ def __exit__(
+ self,
+ unused1: Optional[Type[BaseException]],
+ unused2: Optional[BaseException],
+ unused3: Optional[TracebackType],
+ ) -> None:
+ """Calls deinit()"""
+ ...
+ timeout: float
+
+class Match:
+ """Describe CAN bus messages to match"""
+
+ def __init__(
+ self, id: int, *, mask: Optional[int] = None, extended: bool = False
+ ) -> None:
+ """Construct a Match with the given properties.
+
+ If mask is not None, then the filter is for any id which matches all
+ the nonzero bits in mask. Otherwise, it matches exactly the given id.
+ If extended is true then only extended ids are matched, otherwise
+ only standard ids are matched."""
+ id: int
+ """The id to match"""
+
+ mask: int
+ """The optional mask of ids to match"""
+
+ extended: bool
+ """True to match extended ids, False to match standard ides"""
+
+class Message:
+ def __init__(self, id: int, data: bytes, *, extended: bool = False) -> None:
+ """Construct a Message to send on a CAN bus.
+
+ :param int id: The numeric ID of the message
+ :param bytes data: The content of the message
+ :param bool extended: True if the message has an extended identifier, False if it has a standard identifier
+
+ In CAN, messages can have a length from 0 to 8 bytes.
+ """
+ ...
+ id: int
+ """The numeric ID of the message"""
+
+ data: bytes
+ """The content of the message"""
+
+ extended: bool
+ """True if the message's id is an extended id"""
+
+class RemoteTransmissionRequest:
+ def __init__(self, id: int, length: int, *, extended: bool = False) -> None:
+ """Construct a RemoteTransmissionRequest to send on a CAN bus.
+
+ :param int id: The numeric ID of the requested message
+ :param int length: The length of the requested message
+ :param bool extended: True if the message has an extended identifier, False if it has a standard identifier
+
+ In CAN, messages can have a length from 0 to 8 bytes.
+ """
+ ...
+ id: int
+ """The numeric ID of the message"""
+
+ extended: bool
+ """True if the message's id is an extended id"""
+
+ length: int
+ """The length of the requested message."""
diff --git a/stubs/countio/__init__.pyi b/stubs/countio/__init__.pyi
new file mode 100644
index 0000000..5012487
--- /dev/null
+++ b/stubs/countio/__init__.pyi
@@ -0,0 +1,50 @@
+"""Support for edge counting
+
+The `countio` module contains logic to read and count edge transistions
+
+.. warning:: This module is not available in some SAMD21 (aka M0) builds. See the
+ :ref:`module-support-matrix` for more info.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info."""
+
+from __future__ import annotations
+
+import microcontroller
+
+class Counter:
+ """Counter will keep track of the number of falling edge transistions (pulses) on a
+ given pin"""
+
+ def __init__(self, pin_a: microcontroller.Pin) -> None:
+ """Create a Counter object associated with the given pin. It tracks the number of
+ falling pulses relative when the object is constructed.
+
+ :param ~microcontroller.Pin pin_a: Pin to read pulses from.
+
+
+ For example::
+
+ import countio
+ import time
+ from board import *
+
+ pin_counter = countio.Counter(board.D1)
+ #reset the count after 100 counts
+ while True:
+ if pin_counter.count == 100:
+ pin_counter.reset()
+ print(pin_counter.count)"""
+ def deinit(self) -> None:
+ """Deinitializes the Counter and releases any hardware resources for reuse."""
+ def __enter__(self) -> Counter:
+ """No-op used by Context Managers."""
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ count: int
+ """The current count in terms of pulses."""
+ def reset(self) -> None:
+ """Resets the count back to 0."""
diff --git a/stubs/digitalio/__init__.pyi b/stubs/digitalio/__init__.pyi
new file mode 100644
index 0000000..7cb0acc
--- /dev/null
+++ b/stubs/digitalio/__init__.pyi
@@ -0,0 +1,158 @@
+"""Basic digital pin support
+
+The `digitalio` module contains classes to provide access to basic digital IO.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+For example::
+
+ import digitalio
+ from board import *
+
+ pin = digitalio.DigitalInOut(D13)
+ print(pin.value)
+
+This example will initialize the the device, read
+:py:data:`~digitalio.DigitalInOut.value` and then
+:py:meth:`~digitalio.DigitalInOut.deinit` the hardware.
+
+Here is blinky::
+
+ import digitalio
+ from board import *
+ import time
+
+ led = digitalio.DigitalInOut(D13)
+ led.direction = digitalio.Direction.OUTPUT
+ while True:
+ led.value = True
+ time.sleep(0.1)
+ led.value = False
+ time.sleep(0.1)"""
+
+from __future__ import annotations
+
+from typing import Optional
+
+import microcontroller
+
+class DriveMode:
+ """Defines the drive mode of a digital pin"""
+
+ def __init__(self) -> None:
+ """Enum-like class to define the drive mode used when outputting
+ digital values."""
+ ...
+ PUSH_PULL: DriveMode
+ """Output both high and low digital values"""
+
+ OPEN_DRAIN: DriveMode
+ """Output low digital values but go into high z for digital high. This is
+ useful for i2c and other protocols that share a digital line."""
+
+class DigitalInOut:
+ """Digital input and output
+
+ A DigitalInOut is used to digitally control I/O pins. For analog control of
+ a pin, see the :py:class:`analogio.AnalogIn` and
+ :py:class:`analogio.AnalogOut` classes."""
+
+ def __init__(self, pin: microcontroller.Pin) -> None:
+ """Create a new DigitalInOut object associated with the pin. Defaults to input
+ with no pull. Use :py:meth:`switch_to_input` and
+ :py:meth:`switch_to_output` to change the direction.
+
+ :param ~microcontroller.Pin pin: The pin to control"""
+ ...
+ def deinit(self) -> None:
+ """Turn off the DigitalInOut and release the pin for other use."""
+ ...
+ def __enter__(self) -> DigitalInOut:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def switch_to_output(
+ self, value: bool = False, drive_mode: DriveMode = DriveMode.PUSH_PULL
+ ) -> None:
+ """Set the drive mode and value and then switch to writing out digital
+ values.
+
+ :param bool value: default value to set upon switching
+ :param ~digitalio.DriveMode drive_mode: drive mode for the output
+ """
+ ...
+ def switch_to_input(self, pull: Optional[Pull] = None) -> None:
+ """Set the pull and then switch to read in digital values.
+
+ :param Pull pull: pull configuration for the input
+
+ Example usage::
+
+ import digitalio
+ import board
+
+ switch = digitalio.DigitalInOut(board.SLIDE_SWITCH)
+ switch.switch_to_input(pull=digitalio.Pull.UP)
+ # Or, after switch_to_input
+ switch.pull = digitalio.Pull.UP
+ print(switch.value)"""
+ ...
+ direction: Direction
+ """The direction of the pin.
+
+ Setting this will use the defaults from the corresponding
+ :py:meth:`switch_to_input` or :py:meth:`switch_to_output` method. If
+ you want to set pull, value or drive mode prior to switching, then use
+ those methods instead."""
+
+ value: bool
+ """The digital logic level of the pin."""
+
+ drive_mode: DriveMode
+ """The pin drive mode. One of:
+
+ - `digitalio.DriveMode.PUSH_PULL`
+ - `digitalio.DriveMode.OPEN_DRAIN`"""
+
+ pull: Optional[Pull]
+ """The pin pull direction. One of:
+
+ - `digitalio.Pull.UP`
+ - `digitalio.Pull.DOWN`
+ - `None`
+
+ :raises AttributeError: if `direction` is :py:data:`~digitalio.Direction.OUTPUT`."""
+
+class Direction:
+ """Defines the direction of a digital pin"""
+
+ def __init__(self) -> None:
+ """Enum-like class to define which direction the digital values are
+ going."""
+ ...
+ INPUT: Direction
+ """Read digital data in"""
+
+ OUTPUT: Direction
+ """Write digital data out"""
+
+class Pull:
+ """Defines the pull of a digital input pin"""
+
+ def __init__(self) -> None:
+ """Enum-like class to define the pull value, if any, used while reading
+ digital values in."""
+ ...
+ UP: Pull
+ """When the input line isn't being driven the pull up can pull the state
+ of the line high so it reads as true."""
+
+ DOWN: Pull
+ """When the input line isn't being driven the pull down can pull the
+ state of the line low so it reads as false."""
diff --git a/stubs/displayio/__init__.pyi b/stubs/displayio/__init__.pyi
new file mode 100644
index 0000000..da126e4
--- /dev/null
+++ b/stubs/displayio/__init__.pyi
@@ -0,0 +1,735 @@
+"""Native helpers for driving displays
+
+The `displayio` module contains classes to manage display output
+including synchronizing with refresh rates and partial updating."""
+
+from __future__ import annotations
+
+import typing
+from typing import Optional, Tuple, Union
+
+import busio
+import microcontroller
+import vectorio
+from _typing import ReadableBuffer, WriteableBuffer
+
+def release_displays() -> None:
+ """Releases any actively used displays so their busses and pins can be used again. This will also
+ release the builtin display on boards that have one. You will need to reinitialize it yourself
+ afterwards. This may take seconds to complete if an active EPaperDisplay is refreshing.
+
+ Use this once in your code.py if you initialize a display. Place it right before the
+ initialization so the display is active as long as possible."""
+ ...
+
+class Bitmap:
+ """Stores values of a certain size in a 2D array"""
+
+ def __init__(self, width: int, height: int, value_count: int) -> None:
+ """Create a Bitmap object with the given fixed size. Each pixel stores a value that is used to
+ index into a corresponding palette. This enables differently colored sprites to share the
+ underlying Bitmap. value_count is used to minimize the memory used to store the Bitmap.
+
+ :param int width: The number of values wide
+ :param int height: The number of values high
+ :param int value_count: The number of possible pixel values."""
+ ...
+ width: int
+ """Width of the bitmap. (read only)"""
+
+ height: int
+ """Height of the bitmap. (read only)"""
+ def __getitem__(self, index: Union[Tuple[int, int], int]) -> int:
+ """Returns the value at the given index. The index can either be an x,y tuple or an int equal
+ to ``y * width + x``.
+
+ This allows you to::
+
+ print(bitmap[0,1])"""
+ ...
+ def __setitem__(self, index: Union[Tuple[int, int], int], value: int) -> None:
+ """Sets the value at the given index. The index can either be an x,y tuple or an int equal
+ to ``y * width + x``.
+
+ This allows you to::
+
+ bitmap[0,1] = 3"""
+ ...
+ def blit(
+ self,
+ x: int,
+ y: int,
+ source_bitmap: Bitmap,
+ *,
+ x1: int,
+ y1: int,
+ x2: int,
+ y2: int,
+ skip_index: int
+ ) -> None:
+ """Inserts the source_bitmap region defined by rectangular boundaries
+ (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location.
+
+ :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left
+ corner will be placed
+ :param int y: Vertical pixel location in bitmap where source_bitmap upper-left
+ corner will be placed
+ :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied
+ :param int x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap
+ :param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap
+ :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be copied from the source bitmap
+ :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be copied from the source bitmap
+ :param int skip_index: bitmap palette index in the source that will not be copied,
+ set to None to copy all pixels"""
+ ...
+ def fill(self, value: int) -> None:
+ """Fills the bitmap with the supplied palette index value."""
+ ...
+
+class ColorConverter:
+ """Converts one color format to another."""
+
+ def __init__(self, *, dither: bool = False) -> None:
+ """Create a ColorConverter object to convert color formats. Only supports RGB888 to RGB565
+ currently.
+ :param bool dither: Adds random noise to dither the output image"""
+ ...
+ def convert(self, color: int) -> int:
+ """Converts the given RGB888 color to RGB565"""
+ ...
+ dither: bool
+ """When true the color converter dithers the output by adding random noise when
+ truncating to display bitdepth"""
+ def make_transparent(self, pixel: int) -> None:
+ """Sets a pixel to not opaque."""
+ def make_opaque(self, pixel: int) -> None:
+ """Sets a pixel to opaque."""
+
+_DisplayBus = Union["FourWire", "ParallelBus", "I2CDisplay"]
+""":py:class:`FourWire`, :py:class:`ParallelBus` or :py:class:`I2CDisplay`"""
+
+class Display:
+ """Manage updating a display over a display bus
+
+ This initializes a display and connects it into CircuitPython. Unlike other
+ objects in CircuitPython, Display objects live until `displayio.release_displays()`
+ is called. This is done so that CircuitPython can use the display itself.
+
+ Most people should not use this class directly. Use a specific display driver instead that will
+ contain the initialization sequence at minimum."""
+
+ def __init__(
+ self,
+ display_bus: _DisplayBus,
+ init_sequence: ReadableBuffer,
+ *,
+ width: int,
+ height: int,
+ colstart: int = 0,
+ rowstart: int = 0,
+ rotation: int = 0,
+ color_depth: int = 16,
+ grayscale: bool = False,
+ pixels_in_byte_share_row: bool = True,
+ bytes_per_cell: int = 1,
+ reverse_pixels_in_byte: bool = False,
+ set_column_command: int = 0x2A,
+ set_row_command: int = 0x2B,
+ write_ram_command: int = 0x2C,
+ set_vertical_scroll: int = 0,
+ backlight_pin: Optional[microcontroller.Pin] = None,
+ brightness_command: Optional[int] = None,
+ brightness: float = 1.0,
+ auto_brightness: bool = False,
+ single_byte_bounds: bool = False,
+ data_as_commands: bool = False,
+ auto_refresh: bool = True,
+ native_frames_per_second: int = 60
+ ) -> None:
+ r"""Create a Display object on the given display bus (`FourWire`, `ParallelBus` or `I2CDisplay`).
+
+ The ``init_sequence`` is bitpacked to minimize the ram impact. Every command begins with a
+ command byte followed by a byte to determine the parameter count and delay. When the top bit
+ of the second byte is 1 (0x80), a delay will occur after the command parameters are sent.
+ The remaining 7 bits are the parameter count excluding any delay byte. The bytes following
+ are the parameters. When the delay bit is set, a single byte after the parameters specifies
+ the delay duration in milliseconds. The value 0xff will lead to an extra long 500 ms delay
+ instead of 255 ms. The next byte will begin a new command definition.
+ Here is an example:
+
+ .. code-block:: python
+
+ init_sequence = (b"\xe1\x0f\x00\x0E\x14\x03\x11\x07\x31\xC1\x48\x08\x0F\x0C\x31\x36\x0F" # Set Gamma
+ b"\x11\x80\x78"# Exit Sleep then delay 0x78 (120ms)
+ b"\x29\x81\xaa\x78"# Display on then delay 0x78 (120ms)
+ )
+ display = displayio.Display(display_bus, init_sequence, width=320, height=240)
+
+ The first command is 0xe1 with 15 (0xf) parameters following. The second is 0x11 with 0
+ parameters and a 120ms (0x78) delay. The third command is 0x29 with one parameter 0xaa and a
+ 120ms delay (0x78). Multiple byte literals (b"") are merged together on load. The parens
+ are needed to allow byte literals on subsequent lines.
+
+ The initialization sequence should always leave the display memory access inline with the scan
+ of the display to minimize tearing artifacts.
+
+ :param display_bus: The bus that the display is connected to
+ :type _DisplayBus: FourWire, ParallelBus or I2CDisplay
+ :param ~_typing.ReadableBuffer init_sequence: Byte-packed initialization sequence.
+ :param int width: Width in pixels
+ :param int height: Height in pixels
+ :param int colstart: The index if the first visible column
+ :param int rowstart: The index if the first visible row
+ :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270)
+ :param int color_depth: The number of bits of color per pixel transmitted. (Some displays
+ support 18 bit but 16 is easier to transmit. The last bit is extrapolated.)
+ :param bool grayscale: True if the display only shows a single color.
+ :param bool pixels_in_byte_share_row: True when pixels are less than a byte and a byte includes pixels from the same row of the display. When False, pixels share a column.
+ :param int bytes_per_cell: Number of bytes per addressable memory location when color_depth < 8. When greater than one, bytes share a row or column according to pixels_in_byte_share_row.
+ :param bool reverse_pixels_in_byte: Reverses the pixel order within each byte when color_depth < 8. Does not apply across multiple bytes even if there is more than one byte per cell (bytes_per_cell.)
+ :param bool reverse_bytes_in_word: Reverses the order of bytes within a word when color_depth == 16
+ :param int set_column_command: Command used to set the start and end columns to update
+ :param int set_row_command: Command used so set the start and end rows to update
+ :param int write_ram_command: Command used to write pixels values into the update region. Ignored if data_as_commands is set.
+ :param int set_vertical_scroll: Command used to set the first row to show
+ :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight
+ :param int brightness_command: Command to set display brightness. Usually available in OLED controllers.
+ :param float brightness: Initial display brightness. This value is ignored if auto_brightness is True.
+ :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism.
+ :param bool single_byte_bounds: Display column and row commands use single bytes
+ :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this.
+ :param bool SH1107_addressing: Special quirk for SH1107, use upper/lower column set and page set
+ :param bool auto_refresh: Automatically refresh the screen
+ :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence.
+ :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on."""
+ ...
+ def show(self, group: Group) -> None:
+ """Switches to displaying the given group of layers. When group is None, the default
+ CircuitPython terminal will be shown.
+
+ :param Group group: The group to show."""
+ ...
+ def refresh(
+ self,
+ *,
+ target_frames_per_second: Optional[int] = None,
+ minimum_frames_per_second: int = 1
+ ) -> bool:
+ """When auto refresh is off, waits for the target frame rate and then refreshes the display,
+ returning True. If the call has taken too long since the last refresh call for the given
+ target frame rate, then the refresh returns False immediately without updating the screen to
+ hopefully help getting caught up.
+
+ If the time since the last successful refresh is below the minimum frame rate, then an
+ exception will be raised. Set ``minimum_frames_per_second`` to 0 to disable.
+
+ When auto refresh is off, ``display.refresh()`` or ``display.refresh(target_frames_per_second=None)``
+ will update the display immediately.
+
+ When auto refresh is on, updates the display immediately. (The display will also update
+ without calls to this.)
+
+ :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated.
+ Set to `None` for immediate refresh.
+ :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second."""
+ ...
+ auto_refresh: bool
+ """True when the display is refreshed automatically."""
+
+ brightness: float
+ """The brightness of the display as a float. 0.0 is off and 1.0 is full brightness. When
+ `auto_brightness` is True, the value of `brightness` will change automatically.
+ If `brightness` is set, `auto_brightness` will be disabled and will be set to False."""
+
+ auto_brightness: bool
+ """True when the display brightness is adjusted automatically, based on an ambient
+ light sensor or other method. Note that some displays may have this set to True by default,
+ but not actually implement automatic brightness adjustment. `auto_brightness` is set to False
+ if `brightness` is set manually."""
+
+ width: int
+ """Gets the width of the board"""
+
+ height: int
+ """Gets the height of the board"""
+
+ rotation: int
+ """The rotation of the display as an int in degrees."""
+
+ bus: _DisplayBus
+ """The bus being used by the display"""
+ def fill_row(self, y: int, buffer: WriteableBuffer) -> WriteableBuffer:
+ """Extract the pixels from a single row
+
+ :param int y: The top edge of the area
+ :param ~_typing.WriteableBuffer buffer: The buffer in which to place the pixel data"""
+ ...
+
+class EPaperDisplay:
+ """Manage updating an epaper display over a display bus
+
+ This initializes an epaper display and connects it into CircuitPython. Unlike other
+ objects in CircuitPython, EPaperDisplay objects live until `displayio.release_displays()`
+ is called. This is done so that CircuitPython can use the display itself.
+
+ Most people should not use this class directly. Use a specific display driver instead that will
+ contain the startup and shutdown sequences at minimum."""
+
+ def __init__(
+ self,
+ display_bus: _DisplayBus,
+ start_sequence: ReadableBuffer,
+ stop_sequence: ReadableBuffer,
+ *,
+ width: int,
+ height: int,
+ ram_width: int,
+ ram_height: int,
+ colstart: int = 0,
+ rowstart: int = 0,
+ rotation: int = 0,
+ set_column_window_command: Optional[int] = None,
+ set_row_window_command: Optional[int] = None,
+ single_byte_bounds: bool = False,
+ write_black_ram_command: int,
+ black_bits_inverted: bool = False,
+ write_color_ram_command: Optional[int] = None,
+ color_bits_inverted: bool = False,
+ highlight_color: int = 0x000000,
+ refresh_display_command: int,
+ refresh_time: float = 40,
+ busy_pin: Optional[microcontroller.Pin] = None,
+ busy_state: bool = True,
+ seconds_per_frame: float = 180,
+ always_toggle_chip_select: bool = False,
+ grayscale: bool = False
+ ) -> None:
+ """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`).
+
+ The ``start_sequence`` and ``stop_sequence`` are bitpacked to minimize the ram impact. Every
+ command begins with a command byte followed by a byte to determine the parameter count and
+ delay. When the top bit of the second byte is 1 (0x80), a delay will occur after the command
+ parameters are sent. The remaining 7 bits are the parameter count excluding any delay
+ byte. The bytes following are the parameters. When the delay bit is set, a single byte after
+ the parameters specifies the delay duration in milliseconds. The value 0xff will lead to an
+ extra long 500 ms delay instead of 255 ms. The next byte will begin a new command definition.
+
+ :param display_bus: The bus that the display is connected to
+ :type _DisplayBus: displayio.FourWire or displayio.ParallelBus
+ :param ~_typing.ReadableBuffer start_sequence: Byte-packed initialization sequence.
+ :param ~_typing.ReadableBuffer stop_sequence: Byte-packed initialization sequence.
+ :param int width: Width in pixels
+ :param int height: Height in pixels
+ :param int ram_width: RAM width in pixels
+ :param int ram_height: RAM height in pixels
+ :param int colstart: The index if the first visible column
+ :param int rowstart: The index if the first visible row
+ :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270)
+ :param int set_column_window_command: Command used to set the start and end columns to update
+ :param int set_row_window_command: Command used so set the start and end rows to update
+ :param int set_current_column_command: Command used to set the current column location
+ :param int set_current_row_command: Command used to set the current row location
+ :param int write_black_ram_command: Command used to write pixels values into the update region
+ :param bool black_bits_inverted: True if 0 bits are used to show black pixels. Otherwise, 1 means to show black.
+ :param int write_color_ram_command: Command used to write pixels values into the update region
+ :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color.
+ :param int highlight_color: RGB888 of source color to highlight with third ePaper color.
+ :param int refresh_display_command: Command used to start a display refresh
+ :param float refresh_time: Time it takes to refresh the display before the stop_sequence should be sent. Ignored when busy_pin is provided.
+ :param microcontroller.Pin busy_pin: Pin used to signify the display is busy
+ :param bool busy_state: State of the busy pin when the display is busy
+ :param float seconds_per_frame: Minimum number of seconds between screen refreshes
+ :param bool always_toggle_chip_select: When True, chip select is toggled every byte
+ :param bool grayscale: When true, the color ram is the low bit of 2-bit grayscale"""
+ ...
+ def show(self, group: Group) -> None:
+ """Switches to displaying the given group of layers. When group is None, the default
+ CircuitPython terminal will be shown.
+
+ :param Group group: The group to show."""
+ ...
+ def refresh(self) -> None:
+ """Refreshes the display immediately or raises an exception if too soon. Use
+ ``time.sleep(display.time_to_refresh)`` to sleep until a refresh can occur."""
+ ...
+ time_to_refresh: float
+ """Time, in fractional seconds, until the ePaper display can be refreshed."""
+
+ busy: bool
+ """True when the display is refreshing. This uses the ``busy_pin`` when available or the
+ ``refresh_time`` otherwise."""
+
+ width: int
+ """Gets the width of the display in pixels"""
+
+ height: int
+ """Gets the height of the display in pixels"""
+
+ rotation: int
+ """The rotation of the display as an int in degrees."""
+
+ bus: _DisplayBus
+ """The bus being used by the display"""
+
+class FourWire:
+ """Manage updating a display over SPI four wire protocol in the background while Python code runs.
+ It doesn't handle display initialization."""
+
+ def __init__(
+ self,
+ spi_bus: busio.SPI,
+ *,
+ command: microcontroller.Pin,
+ chip_select: microcontroller.Pin,
+ reset: Optional[microcontroller.Pin] = None,
+ baudrate: int = 24000000,
+ polarity: int = 0,
+ phase: int = 0
+ ) -> None:
+ """Create a FourWire object associated with the given pins.
+
+ The SPI bus and pins are then in use by the display until `displayio.release_displays()` is
+ called even after a reload. (It does this so CircuitPython can use the display after your code
+ is done.) So, the first time you initialize a display bus in code.py you should call
+ :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run.
+
+ :param busio.SPI spi_bus: The SPI bus that make up the clock and data lines
+ :param microcontroller.Pin command: Data or command pin
+ :param microcontroller.Pin chip_select: Chip select pin
+ :param microcontroller.Pin reset: Reset pin. When None only software reset can be used
+ :param int baudrate: Maximum baudrate in Hz for the display on the bus
+ :param int polarity: the base state of the clock line (0 or 1)
+ :param int phase: the edge of the clock that data is captured. First (0)
+ or second (1). Rising or falling depends on clock polarity."""
+ ...
+ def reset(self) -> None:
+ """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin
+ is available."""
+ ...
+ def send(
+ self, command: int, data: FourWire, *, toggle_every_byte: bool = False
+ ) -> None:
+ """Sends the given command value followed by the full set of data. Display state, such as
+ vertical scroll, set via ``send`` may or may not be reset once the code is done."""
+ ...
+
+class Group:
+ """Manage a group of sprites and groups and how they are inter-related."""
+
+ def __init__(
+ self, *, max_size: int = 4, scale: int = 1, x: int = 0, y: int = 0
+ ) -> None:
+ """Create a Group of a given size and scale. Scale is in one dimension. For example, scale=2
+ leads to a layer's pixel being 2x2 pixels when in the group.
+
+ :param int max_size: The maximum group size.
+ :param int scale: Scale of layer pixels in one dimension.
+ :param int x: Initial x position within the parent.
+ :param int y: Initial y position within the parent."""
+ ...
+ hidden: bool
+ """True when the Group and all of it's layers are not visible. When False, the Group's layers
+ are visible if they haven't been hidden."""
+
+ scale: int
+ """Scales each pixel within the Group in both directions. For example, when scale=2 each pixel
+ will be represented by 2x2 pixels."""
+
+ x: int
+ """X position of the Group in the parent."""
+
+ y: int
+ """Y position of the Group in the parent."""
+ def append(self, layer: Union[vectorio.VectorShape, Group, TileGrid]) -> None:
+ """Append a layer to the group. It will be drawn above other layers."""
+ ...
+ def insert(
+ self, index: int, layer: Union[vectorio.VectorShape, Group, TileGrid]
+ ) -> None:
+ """Insert a layer into the group."""
+ ...
+ def index(self, layer: Union[vectorio.VectorShape, Group, TileGrid]) -> int:
+ """Returns the index of the first copy of layer. Raises ValueError if not found."""
+ ...
+ def pop(self, i: int = -1) -> Union[vectorio.VectorShape, Group, TileGrid]:
+ """Remove the ith item and return it."""
+ ...
+ def remove(self, layer: Union[vectorio.VectorShape, Group, TileGrid]) -> None:
+ """Remove the first copy of layer. Raises ValueError if it is not present."""
+ ...
+ def __bool__(self) -> bool: ...
+ def __len__(self) -> int:
+ """Returns the number of layers in a Group"""
+ ...
+ def __getitem__(self, index: int) -> Union[vectorio.VectorShape, Group, TileGrid]:
+ """Returns the value at the given index.
+
+ This allows you to::
+
+ print(group[0])"""
+ ...
+ def __setitem__(
+ self, index: int, value: Union[vectorio.VectorShape, Group, TileGrid]
+ ) -> None:
+ """Sets the value at the given index.
+
+ This allows you to::
+
+ group[0] = sprite"""
+ ...
+ def __delitem__(self, index: int) -> None:
+ """Deletes the value at the given index.
+
+ This allows you to::
+
+ del group[0]"""
+ ...
+
+class I2CDisplay:
+ """Manage updating a display over I2C in the background while Python code runs.
+ It doesn't handle display initialization."""
+
+ def __init__(
+ self,
+ i2c_bus: busio.I2C,
+ *,
+ device_address: int,
+ reset: Optional[microcontroller.Pin] = None
+ ) -> None:
+ """Create a I2CDisplay object associated with the given I2C bus and reset pin.
+
+ The I2C bus and pins are then in use by the display until `displayio.release_displays()` is
+ called even after a reload. (It does this so CircuitPython can use the display after your code
+ is done.) So, the first time you initialize a display bus in code.py you should call
+ :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run.
+
+ :param busio.I2C i2c_bus: The I2C bus that make up the clock and data lines
+ :param int device_address: The I2C address of the device
+ :param microcontroller.Pin reset: Reset pin. When None only software reset can be used"""
+ ...
+ def reset(self) -> None:
+ """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin
+ is available."""
+ ...
+ def send(self, command: int, data: ReadableBuffer) -> None:
+ """Sends the given command value followed by the full set of data. Display state, such as
+ vertical scroll, set via ``send`` may or may not be reset once the code is done."""
+ ...
+
+class OnDiskBitmap:
+ """Loads values straight from disk. This minimizes memory use but can lead to
+ much slower pixel load times. These load times may result in frame tearing where only part of
+ the image is visible.
+
+ It's easiest to use on a board with a built in display such as the `Hallowing M0 Express
+ `_.
+
+ .. code-block:: Python
+
+ import board
+ import displayio
+ import time
+ import pulseio
+
+ board.DISPLAY.auto_brightness = False
+ board.DISPLAY.brightness = 0
+ splash = displayio.Group()
+ board.DISPLAY.show(splash)
+
+ with open("/sample.bmp", "rb") as f:
+ odb = displayio.OnDiskBitmap(f)
+ face = displayio.TileGrid(odb, pixel_shader=displayio.ColorConverter())
+ splash.append(face)
+ # Wait for the image to load.
+ board.DISPLAY.refresh(target_frames_per_second=60)
+
+ # Fade up the backlight
+ for i in range(100):
+ board.DISPLAY.brightness = 0.01 * i
+ time.sleep(0.05)
+
+ # Wait forever
+ while True:
+ pass"""
+
+ def __init__(self, file: typing.BinaryIO) -> None:
+ """Create an OnDiskBitmap object with the given file.
+
+ :param file file: The open bitmap file"""
+ ...
+ width: int
+ """Width of the bitmap. (read only)"""
+
+ height: int
+ """Height of the bitmap. (read only)"""
+
+class Palette:
+ """Map a pixel palette_index to a full color. Colors are transformed to the display's format internally to
+ save memory."""
+
+ def __init__(self, color_count: int) -> None:
+ """Create a Palette object to store a set number of colors.
+
+ :param int color_count: The number of colors in the Palette"""
+ ...
+ def __bool__(self) -> bool: ...
+ def __len__(self) -> int:
+ """Returns the number of colors in a Palette"""
+ ...
+ def __getitem__(self, index: int) -> Optional[int]:
+ r"""Return the pixel color at the given index as an integer."""
+ ...
+ def __setitem__(
+ self, index: int, value: Union[int, ReadableBuffer, Tuple[int, int, int]]
+ ) -> None:
+ r"""Sets the pixel color at the given index. The index should be an integer in the range 0 to color_count-1.
+
+ The value argument represents a color, and can be from 0x000000 to 0xFFFFFF (to represent an RGB value).
+ Value can be an int, bytes (3 bytes (RGB) or 4 bytes (RGB + pad byte)), bytearray,
+ or a tuple or list of 3 integers.
+
+ This allows you to::
+
+ palette[0] = 0xFFFFFF # set using an integer
+ palette[1] = b'\xff\xff\x00' # set using 3 bytes
+ palette[2] = b'\xff\xff\x00\x00' # set using 4 bytes
+ palette[3] = bytearray(b'\x00\x00\xFF') # set using a bytearay of 3 or 4 bytes
+ palette[4] = (10, 20, 30) # set using a tuple of 3 integers"""
+ ...
+ def make_transparent(self, palette_index: int) -> None: ...
+ def make_opaque(self, palette_index: int) -> None: ...
+
+class ParallelBus:
+ """Manage updating a display over 8-bit parallel bus in the background while Python code runs. This
+ protocol may be refered to as 8080-I Series Parallel Interface in datasheets. It doesn't handle
+ display initialization."""
+
+ def __init__(
+ self,
+ *,
+ data0: microcontroller.Pin,
+ command: microcontroller.Pin,
+ chip_select: microcontroller.Pin,
+ write: microcontroller.Pin,
+ read: microcontroller.Pin,
+ reset: microcontroller.Pin
+ ) -> None:
+ """Create a ParallelBus object associated with the given pins. The bus is inferred from data0
+ by implying the next 7 additional pins on a given GPIO port.
+
+ The parallel bus and pins are then in use by the display until `displayio.release_displays()`
+ is called even after a reload. (It does this so CircuitPython can use the display after your
+ code is done.) So, the first time you initialize a display bus in code.py you should call
+ :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run.
+
+ :param microcontroller.Pin data0: The first data pin. The rest are implied
+ :param microcontroller.Pin command: Data or command pin
+ :param microcontroller.Pin chip_select: Chip select pin
+ :param microcontroller.Pin write: Write pin
+ :param microcontroller.Pin read: Read pin
+ :param microcontroller.Pin reset: Reset pin"""
+ ...
+ def reset(self) -> None:
+ """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin
+ is available."""
+ ...
+ def send(self, command: int, data: ReadableBuffer) -> None:
+ """Sends the given command value followed by the full set of data. Display state, such as
+ vertical scroll, set via ``send`` may or may not be reset once the code is done."""
+ ...
+
+class Shape:
+ """Represents a shape made by defining boundaries that may be mirrored."""
+
+ def __init__(
+ self, width: int, height: int, *, mirror_x: bool = False, mirror_y: bool = False
+ ) -> None:
+ """Create a Shape object with the given fixed size. Each pixel is one bit and is stored by the
+ column boundaries of the shape on each row. Each row's boundary defaults to the full row.
+
+ :param int width: The number of pixels wide
+ :param int height: The number of pixels high
+ :param bool mirror_x: When true the left boundary is mirrored to the right.
+ :param bool mirror_y: When true the top boundary is mirrored to the bottom."""
+ ...
+ def set_boundary(self, y: int, start_x: int, end_x: int) -> None:
+ """Loads pre-packed data into the given row."""
+ ...
+
+class TileGrid:
+ """A grid of tiles sourced out of one bitmap
+
+ Position a grid of tiles sourced from a bitmap and pixel_shader combination. Multiple grids
+ can share bitmaps and pixel shaders.
+
+ A single tile grid is also known as a Sprite."""
+
+ def __init__(
+ self,
+ bitmap: Bitmap,
+ *,
+ pixel_shader: Union[ColorConverter, Palette],
+ width: int = 1,
+ height: int = 1,
+ tile_width: Optional[int] = None,
+ tile_height: Optional[int] = None,
+ default_tile: int = 0,
+ x: int = 0,
+ y: int = 0
+ ) -> None:
+ """Create a TileGrid object. The bitmap is source for 2d pixels. The pixel_shader is used to
+ convert the value and its location to a display native pixel color. This may be a simple color
+ palette lookup, a gradient, a pattern or a color transformer.
+
+ tile_width and tile_height match the height of the bitmap by default.
+
+ :param Bitmap bitmap: The bitmap storing one or more tiles.
+ :param ColorConverter or Palette pixel_shader: The pixel shader that produces colors from values
+ :param int width: Width of the grid in tiles.
+ :param int height: Height of the grid in tiles.
+ :param int tile_width: Width of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions.
+ :param int tile_height: Height of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions.
+ :param int default_tile: Default tile index to show.
+ :param int x: Initial x position of the left edge within the parent.
+ :param int y: Initial y position of the top edge within the parent."""
+ hidden: bool
+ """True when the TileGrid is hidden. This may be False even when a part of a hidden Group."""
+
+ x: int
+ """X position of the left edge in the parent."""
+
+ y: int
+ """Y position of the top edge in the parent."""
+
+ flip_x: bool
+ """If true, the left edge rendered will be the right edge of the right-most tile."""
+
+ flip_y: bool
+ """If true, the top edge rendered will be the bottom edge of the bottom-most tile."""
+
+ transpose_xy: bool
+ """If true, the TileGrid's axis will be swapped. When combined with mirroring, any 90 degree
+ rotation can be achieved along with the corresponding mirrored version."""
+
+ pixel_shader: Union[ColorConverter, Palette]
+ """The pixel shader of the tilegrid."""
+ def __getitem__(self, index: Union[Tuple[int, int], int]) -> int:
+ """Returns the tile index at the given index. The index can either be an x,y tuple or an int equal
+ to ``y * width + x``.
+
+ This allows you to::
+
+ print(grid[0])"""
+ ...
+ def __setitem__(self, index: Union[Tuple[int, int], int], value: int) -> None:
+ """Sets the tile index at the given index. The index can either be an x,y tuple or an int equal
+ to ``y * width + x``.
+
+ This allows you to::
+
+ grid[0] = 10
+
+ or::
+
+ grid[0,0] = 10"""
+ ...
diff --git a/stubs/fontio/__init__.pyi b/stubs/fontio/__init__.pyi
new file mode 100644
index 0000000..76d6f48
--- /dev/null
+++ b/stubs/fontio/__init__.pyi
@@ -0,0 +1,52 @@
+"""Core font related data structures"""
+
+from __future__ import annotations
+
+from typing import Tuple
+
+import displayio
+
+class BuiltinFont:
+ """A font built into CircuitPython"""
+
+ def __init__(self) -> None:
+ """Creation not supported. Available fonts are defined when CircuitPython is built. See the
+ `Adafruit_CircuitPython_Bitmap_Font `_
+ library for dynamically loaded fonts."""
+ ...
+ bitmap: displayio.Bitmap
+ """Bitmap containing all font glyphs starting with ASCII and followed by unicode. Use
+ `get_glyph` in most cases. This is useful for use with `displayio.TileGrid` and
+ `terminalio.Terminal`."""
+ def get_bounding_box(self) -> Tuple[int, int]:
+ """Returns the maximum bounds of all glyphs in the font in a tuple of two values: width, height."""
+ ...
+ def get_glyph(self, codepoint: int) -> Glyph:
+ """Returns a `fontio.Glyph` for the given codepoint or None if no glyph is available."""
+ ...
+
+class Glyph:
+ """Storage of glyph info"""
+
+ def __init__(
+ self,
+ bitmap: displayio.Bitmap,
+ tile_index: int,
+ width: int,
+ height: int,
+ dx: int,
+ dy: int,
+ shift_x: int,
+ shift_y: int,
+ ) -> None:
+ """Named tuple used to capture a single glyph and its attributes.
+
+ :param bitmap: the bitmap including the glyph
+ :param tile_index: the tile index within the bitmap
+ :param width: the width of the glyph's bitmap
+ :param height: the height of the glyph's bitmap
+ :param dx: x adjustment to the bitmap's position
+ :param dy: y adjustment to the bitmap's position
+ :param shift_x: the x difference to the next glyph
+ :param shift_y: the y difference to the next glyph"""
+ ...
diff --git a/stubs/framebufferio/__init__.pyi b/stubs/framebufferio/__init__.pyi
new file mode 100644
index 0000000..2d0d0a3
--- /dev/null
+++ b/stubs/framebufferio/__init__.pyi
@@ -0,0 +1,88 @@
+"""Native framebuffer display driving
+
+The `framebufferio` module contains classes to manage display output
+including synchronizing with refresh rates and partial updating.
+It is used in conjunction with classes from `displayio` to actually
+place items on the display; and classes like `RGBMatrix` to actually
+drive the display."""
+
+from __future__ import annotations
+
+import _typing
+import displayio
+from _typing import WriteableBuffer
+
+class FramebufferDisplay:
+ """Manage updating a display with framebuffer in RAM
+
+ This initializes a display and connects it into CircuitPython. Unlike other
+ objects in CircuitPython, Display objects live until `displayio.release_displays()`
+ is called. This is done so that CircuitPython can use the display itself."""
+
+ def __init__(
+ self,
+ framebuffer: _typing.FrameBuffer,
+ *,
+ rotation: int = 0,
+ auto_refresh: bool = True
+ ) -> None:
+ """Create a Display object with the given framebuffer (a buffer, array, ulab.array, etc)
+
+ :param ~_typing.FrameBuffer framebuffer: The framebuffer that the display is connected to
+ :param bool auto_refresh: Automatically refresh the screen
+ :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270)"""
+ ...
+ def show(self, group: displayio.Group) -> None:
+ """Switches to displaying the given group of layers. When group is None, the default
+ CircuitPython terminal will be shown.
+
+ :param Group group: The group to show."""
+ ...
+ def refresh(
+ self, *, target_frames_per_second: int = 60, minimum_frames_per_second: int = 1
+ ) -> bool:
+ """When auto refresh is off, waits for the target frame rate and then refreshes the display,
+ returning True. If the call has taken too long since the last refresh call for the given
+ target frame rate, then the refresh returns False immediately without updating the screen to
+ hopefully help getting caught up.
+
+ If the time since the last successful refresh is below the minimum frame rate, then an
+ exception will be raised. Set minimum_frames_per_second to 0 to disable.
+
+ When auto refresh is on, updates the display immediately. (The display will also update
+ without calls to this.)
+
+ :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated.
+ :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second."""
+ ...
+ auto_refresh: bool
+ """True when the display is refreshed automatically."""
+
+ brightness: float
+ """The brightness of the display as a float. 0.0 is off and 1.0 is full brightness. When
+ `auto_brightness` is True, the value of `brightness` will change automatically.
+ If `brightness` is set, `auto_brightness` will be disabled and will be set to False."""
+
+ auto_brightness: bool
+ """True when the display brightness is adjusted automatically, based on an ambient
+ light sensor or other method. Note that some displays may have this set to True by default,
+ but not actually implement automatic brightness adjustment. `auto_brightness` is set to False
+ if `brightness` is set manually."""
+
+ width: int
+ """Gets the width of the framebuffer"""
+
+ height: int
+ """Gets the height of the framebuffer"""
+
+ rotation: int
+ """The rotation of the display as an int in degrees."""
+
+ framebuffer: _typing.FrameBuffer
+ """The framebuffer being used by the display"""
+ def fill_row(self, y: int, buffer: WriteableBuffer) -> WriteableBuffer:
+ """Extract the pixels from a single row
+
+ :param int y: The top edge of the area
+ :param ~_typing.WriteableBuffer buffer: The buffer in which to place the pixel data"""
+ ...
diff --git a/stubs/frequencyio/__init__.pyi b/stubs/frequencyio/__init__.pyi
new file mode 100644
index 0000000..d332448
--- /dev/null
+++ b/stubs/frequencyio/__init__.pyi
@@ -0,0 +1,94 @@
+"""Support for frequency based protocols
+
+.. warning:: This module is not available in SAMD21 builds. See the
+ :ref:`module-support-matrix` for more info.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+For example::
+
+ import frequencyio
+ import time
+ from board import *
+
+ frequency = frequencyio.FrequencyIn(D13)
+ frequency.capture_period = 15
+ time.sleep(0.1)
+
+This example will initialize the the device, set
+:py:data:`~frequencyio.FrequencyIn.capture_period`, and then sleep 0.1 seconds.
+CircuitPython will automatically turn off FrequencyIn capture when it resets all
+hardware after program completion. Use ``deinit()`` or a ``with`` statement
+to do it yourself."""
+
+from __future__ import annotations
+
+import microcontroller
+
+class FrequencyIn:
+ """Read a frequency signal
+
+ FrequencyIn is used to measure the frequency, in hertz, of a digital signal
+ on an incoming pin. Accuracy has shown to be within 10%, if not better. It
+ is recommended to utilize an average of multiple samples to smooth out readings.
+
+ Frequencies below 1KHz are not currently detectable.
+
+ FrequencyIn will not determine pulse width (use ``PulseIn``)."""
+
+ def __init__(self, pin: microcontroller.Pin, capture_period: int = 10) -> None:
+ """Create a FrequencyIn object associated with the given pin.
+
+ :param ~microcontroller.Pin pin: Pin to read frequency from.
+ :param int capture_period: Keyword argument to set the measurement period, in
+ milliseconds. Default is 10ms; range is 1ms - 500ms.
+
+ Read the incoming frequency from a pin::
+
+ import frequencyio
+ import board
+
+ frequency = frequencyio.FrequencyIn(board.D11)
+
+ # Loop while printing the detected frequency
+ while True:
+ print(frequency.value)
+
+ # Optional clear() will reset the value
+ # to zero. Without this, if the incoming
+ # signal stops, the last reading will remain
+ # as the value.
+ frequency.clear()"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the FrequencyIn and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> FrequencyIn:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def pause(self) -> None:
+ """Pause frequency capture."""
+ ...
+ def resume(self) -> None:
+ """Resumes frequency capture."""
+ ...
+ def clear(self) -> None:
+ """Clears the last detected frequency capture value."""
+ ...
+ capture_period: int
+ """The capture measurement period. Lower incoming frequencies will be measured
+ more accurately with longer capture periods. Higher frequencies are more
+ accurate with shorter capture periods.
+
+ .. note:: When setting a new ``capture_period``, all previous capture information is
+ cleared with a call to ``clear()``."""
+ def __get__(self, index: int) -> int:
+ """Returns the value of the last frequency captured."""
+ ...
diff --git a/stubs/gamepad/__init__.pyi b/stubs/gamepad/__init__.pyi
new file mode 100644
index 0000000..32f2cf1
--- /dev/null
+++ b/stubs/gamepad/__init__.pyi
@@ -0,0 +1,83 @@
+"""Button handling in the background"""
+
+from __future__ import annotations
+
+import digitalio
+
+class GamePad:
+ """Scan buttons for presses
+
+ Usage::
+
+ import board
+ import digitalio
+ import gamepad
+ import time
+
+ B_UP = 1 << 0
+ B_DOWN = 1 << 1
+
+
+ pad = gamepad.GamePad(
+ digitalio.DigitalInOut(board.D10),
+ digitalio.DigitalInOut(board.D11),
+ )
+
+ y = 0
+ while True:
+ buttons = pad.get_pressed()
+ if buttons & B_UP:
+ y -= 1
+ print(y)
+ elif buttons & B_DOWN:
+ y += 1
+ print(y)
+ time.sleep(0.1)
+ while buttons:
+ # Wait for all buttons to be released.
+ buttons = pad.get_pressed()
+ time.sleep(0.1)"""
+
+ def __init__(
+ self,
+ b1: digitalio.DigitalInOut,
+ b2: digitalio.DigitalInOut,
+ b3: digitalio.DigitalInOut,
+ b4: digitalio.DigitalInOut,
+ b5: digitalio.DigitalInOut,
+ b6: digitalio.DigitalInOut,
+ b7: digitalio.DigitalInOut,
+ b8: digitalio.DigitalInOut,
+ ) -> None:
+ """Initializes button scanning routines.
+
+ The ``b1``-``b8`` parameters are ``DigitalInOut`` objects, which
+ immediately get switched to input with a pull-up, (unless they already
+ were set to pull-down, in which case they remain so), and then scanned
+ regularly for button presses. The order is the same as the order of
+ bits returned by the ``get_pressed`` function. You can re-initialize
+ it with different keys, then the new object will replace the previous
+ one.
+
+ The basic feature required here is the ability to poll the keys at
+ regular intervals (so that de-bouncing is consistent) and fast enough
+ (so that we don't miss short button presses) while at the same time
+ letting the user code run normally, call blocking functions and wait
+ on delays.
+
+ They button presses are accumulated, until the ``get_pressed`` method
+ is called, at which point the button state is cleared, and the new
+ button presses start to be recorded."""
+ ...
+ def get_pressed(self) -> int:
+ """Get the status of buttons pressed since the last call and clear it.
+
+ Returns an 8-bit number, with bits that correspond to buttons,
+ which have been pressed (or held down) since the last call to this
+ function set to 1, and the remaining bits set to 0. Then it clears
+ the button state, so that new button presses (or buttons that are
+ held down) can be recorded for the next call."""
+ ...
+ def deinit(self) -> None:
+ """Disable button scanning."""
+ ...
diff --git a/stubs/gamepadshift/__init__.pyi b/stubs/gamepadshift/__init__.pyi
new file mode 100644
index 0000000..68e4d2c
--- /dev/null
+++ b/stubs/gamepadshift/__init__.pyi
@@ -0,0 +1,39 @@
+"""Tracks button presses read through a shift register"""
+
+from __future__ import annotations
+
+import digitalio
+
+class GamePadShift:
+ """Scan buttons for presses through a shift register"""
+
+ def __init__(
+ self,
+ clock: digitalio.DigitalInOut,
+ data: digitalio.DigitalInOut,
+ latch: digitalio.DigitalInOut,
+ ) -> None:
+ """Initializes button scanning routines.
+
+ The ``clock``, ``data`` and ``latch`` parameters are ``DigitalInOut``
+ objects connected to the shift register controlling the buttons.
+
+ They button presses are accumulated, until the ``get_pressed`` method
+ is called, at which point the button state is cleared, and the new
+ button presses start to be recorded.
+
+ Only one gamepad (`gamepad.GamePad` or `gamepadshift.GamePadShift`)
+ may be used at a time."""
+ ...
+ def get_pressed(self) -> int:
+ """Get the status of buttons pressed since the last call and clear it.
+
+ Returns an 8-bit number, with bits that correspond to buttons,
+ which have been pressed (or held down) since the last call to this
+ function set to 1, and the remaining bits set to 0. Then it clears
+ the button state, so that new button presses (or buttons that are
+ held down) can be recorded for the next call."""
+ ...
+ def deinit(self) -> None:
+ """Disable button scanning."""
+ ...
diff --git a/stubs/gnss/__init__.pyi b/stubs/gnss/__init__.pyi
new file mode 100644
index 0000000..489119a
--- /dev/null
+++ b/stubs/gnss/__init__.pyi
@@ -0,0 +1,89 @@
+"""Global Navigation Satellite System
+
+The `gnss` module contains classes to control the GNSS and acquire positioning information."""
+
+from __future__ import annotations
+
+import time
+from typing import List, Union
+
+class GNSS:
+ """Get updated positioning information from Global Navigation Satellite System (GNSS)
+
+ Usage::
+
+ import gnss
+ import time
+
+ nav = gnss.GNSS([gnss.SatelliteSystem.GPS, gnss.SatelliteSystem.GLONASS])
+ last_print = time.monotonic()
+ while True:
+ nav.update()
+ current = time.monotonic()
+ if current - last_print >= 1.0:
+ last_print = current
+ if nav.fix is gnss.PositionFix.INVALID:
+ print("Waiting for fix...")
+ continue
+ print("Latitude: {0:.6f} degrees".format(nav.latitude))
+ print("Longitude: {0:.6f} degrees".format(nav.longitude))"""
+
+ def __init__(self, system: Union[SatelliteSystem, List[SatelliteSystem]]) -> None:
+ """Turn on the GNSS.
+
+ :param system: satellite system to use"""
+ ...
+ def deinit(self) -> None:
+ """Turn off the GNSS."""
+ ...
+ def update(self) -> None:
+ """Update GNSS positioning information."""
+ ...
+ latitude: float
+ """Latitude of current position in degrees (float)."""
+
+ longitude: float
+ """Longitude of current position in degrees (float)."""
+
+ altitude: float
+ """Altitude of current position in meters (float)."""
+
+ timestamp: time.struct_time
+ """Time when the position data was updated."""
+
+ fix: PositionFix
+ """Fix mode."""
+
+class PositionFix:
+ """Position fix mode"""
+
+ def __init__(self) -> None:
+ """Enum-like class to define the position fix mode."""
+ INVALID: PositionFix
+ """No measurement."""
+
+ FIX_2D: PositionFix
+ """2D fix."""
+
+ FIX_3D: PositionFix
+ """3D fix."""
+
+class SatelliteSystem:
+ """Satellite system type"""
+
+ def __init__(self) -> None:
+ """Enum-like class to define the satellite system type."""
+ GPS: SatelliteSystem
+ """Global Positioning System."""
+
+ GLONASS: SatelliteSystem
+ """GLObal NAvigation Satellite System."""
+
+ SBAS: SatelliteSystem
+ """Satellite Based Augmentation System."""
+
+ QZSS_L1CA: SatelliteSystem
+ """Quasi-Zenith Satellite System L1C/A."""
+
+ QZSS_L1S: SatelliteSystem
+ """Quasi-Zenith Satellite System L1S."""
diff --git a/stubs/i2cperipheral/__init__.pyi b/stubs/i2cperipheral/__init__.pyi
new file mode 100644
index 0000000..8e2d322
--- /dev/null
+++ b/stubs/i2cperipheral/__init__.pyi
@@ -0,0 +1,150 @@
+"""Two wire serial protocol peripheral
+
+The `i2cperipheral` module contains classes to support an I2C peripheral.
+
+Example emulating a peripheral with 2 addresses (read and write)::
+
+ import board
+ from i2cperipheral import I2CPeripheral
+
+ regs = [0] * 16
+ index = 0
+
+ with I2CPeripheral(board.SCL, board.SDA, (0x40, 0x41)) as device:
+ while True:
+ r = device.request()
+ if not r:
+ # Maybe do some housekeeping
+ continue
+ with r: # Closes the transfer if necessary by sending a NACK or feeding dummy bytes
+ if r.address == 0x40:
+ if not r.is_read: # Main write which is Selected read
+ b = r.read(1)
+ if not b or b[0] > 15:
+ break
+ index = b[0]
+ b = r.read(1)
+ if b:
+ regs[index] = b[0]
+ elif r.is_restart: # Combined transfer: This is the Main read message
+ n = r.write(bytes([regs[index]]))
+ #else:
+ # A read transfer is not supported in this example
+ # If the microcontroller tries, it will get 0xff byte(s) by the ctx manager (r.close())
+ elif r.address == 0x41:
+ if not r.is_read:
+ b = r.read(1)
+ if b and b[0] == 0xde:
+ # do something
+ pass
+
+This example sets up an I2C device that can be accessed from Linux like this::
+
+ $ i2cget -y 1 0x40 0x01
+ 0x00
+ $ i2cset -y 1 0x40 0x01 0xaa
+ $ i2cget -y 1 0x40 0x01
+ 0xaa
+
+.. warning::
+ I2CPeripheral makes use of clock stretching in order to slow down
+ the host.
+ Make sure the I2C host supports this.
+
+ Raspberry Pi in particular does not support this with its I2C hw block.
+ This can be worked around by using the ``i2c-gpio`` bit banging driver.
+ Since the RPi firmware uses the hw i2c, it's not possible to emulate a HAT eeprom."""
+
+from __future__ import annotations
+
+from typing import Sequence
+
+import i2cperipheral
+import microcontroller
+from _typing import ReadableBuffer
+
+class I2CPeripheral:
+ """Two wire serial protocol peripheral"""
+
+ def __init__(
+ self,
+ scl: microcontroller.Pin,
+ sda: microcontroller.Pin,
+ addresses: Sequence[int],
+ smbus: bool = False,
+ ) -> None:
+ """I2C is a two-wire protocol for communicating between devices.
+ This implements the peripheral (sensor, secondary) side.
+
+ :param ~microcontroller.Pin scl: The clock pin
+ :param ~microcontroller.Pin sda: The data pin
+ :param addresses: The I2C addresses to respond to (how many is hw dependent).
+ :type addresses: list[int]
+ :param bool smbus: Use SMBUS timings if the hardware supports it"""
+ ...
+ def deinit(self) -> None:
+ """Releases control of the underlying hardware so other classes can use it."""
+ ...
+ def __enter__(self) -> I2CPeripheral:
+ """No-op used in Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware on context exit. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def request(self, timeout: float = -1) -> I2CPeripheralRequest:
+ """Wait for an I2C request.
+
+ :param float timeout: Timeout in seconds. Zero means wait forever, a negative value means check once
+ :return: I2C Slave Request or None if timeout=-1 and there's no request
+ :rtype: ~i2cperipheral.I2CPeripheralRequest"""
+
+class I2CPeripheralRequest:
+ def __init__(
+ self,
+ peripheral: i2cperipheral.I2CPeripheral,
+ address: int,
+ is_read: bool,
+ is_restart: bool,
+ ) -> None:
+ """Information about an I2C transfer request
+ This cannot be instantiated directly, but is returned by :py:meth:`I2CPeripheral.request`.
+
+ :param peripheral: The I2CPeripheral object receiving this request
+ :param address: I2C address
+ :param is_read: True if the main peripheral is requesting data
+ :param is_restart: Repeated Start Condition"""
+ def __enter__(self) -> I2CPeripheralRequest:
+ """No-op used in Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Close the request."""
+ ...
+ address: int
+ """The I2C address of the request."""
+
+ is_read: bool
+ """The I2C main controller is reading from this peripheral."""
+
+ is_restart: bool
+ """Is Repeated Start Condition."""
+ def read(self, n: int = -1, ack: bool = True) -> bytearray:
+ """Read data.
+ If ack=False, the caller is responsible for calling :py:meth:`I2CPeripheralRequest.ack`.
+
+ :param n: Number of bytes to read (negative means all)
+ :param ack: Whether or not to send an ACK after the n'th byte
+ :return: Bytes read"""
+ ...
+ def write(self, buffer: ReadableBuffer) -> int:
+ """Write the data contained in buffer.
+
+ :param ~_typing.ReadableBuffer buffer: Write out the data in this buffer
+ :return: Number of bytes written"""
+ ...
+ def ack(self, ack: bool = True) -> None:
+ """Acknowledge or Not Acknowledge last byte received.
+ Use together with :py:meth:`I2CPeripheralRequest.read` ack=False.
+
+ :param ack: Whether to send an ACK or NACK"""
+ ...
diff --git a/stubs/ipaddress/__init__.pyi b/stubs/ipaddress/__init__.pyi
new file mode 100644
index 0000000..bd06044
--- /dev/null
+++ b/stubs/ipaddress/__init__.pyi
@@ -0,0 +1,32 @@
+"""
+The `ipaddress` module provides types for IP addresses. It is a subset of CPython's ipaddress
+module.
+"""
+
+from __future__ import annotations
+
+from typing import Union
+
+def ip_address(obj: Union[int]) -> IPv4Address:
+ """Return a corresponding IP address object or raise ValueError if not possible."""
+ ...
+
+class IPv4Address:
+ """Encapsulates an IPv4 address."""
+
+ def __init__(self, address: Union[int, str, bytes]) -> None:
+ """Create a new IPv4Address object encapsulating the address value.
+
+ The value itself can either be bytes or a string formatted address."""
+ ...
+ packed: bytes
+ """The bytes that make up the address (read-only)."""
+
+ version: int
+ """4 for IPv4, 6 for IPv6"""
+ def __eq__(self, other: object) -> bool:
+ """Two Address objects are equal if their addresses and address types are equal."""
+ ...
+ def __hash__(self) -> int:
+ """Returns a hash for the IPv4Address data."""
+ ...
diff --git a/stubs/math/__init__.pyi b/stubs/math/__init__.pyi
new file mode 100644
index 0000000..cc165a8
--- /dev/null
+++ b/stubs/math/__init__.pyi
@@ -0,0 +1,164 @@
+"""mathematical functions
+
+The `math` module provides some basic mathematical functions for
+working with floating-point numbers."""
+
+from __future__ import annotations
+
+from typing import Tuple
+
+e: float
+"""base of the natural logarithm"""
+
+pi: float
+"""the ratio of a circle's circumference to its diameter"""
+
+def acos(x: float) -> float:
+ """Return the inverse cosine of ``x``."""
+ ...
+
+def asin(x: float) -> float:
+ """Return the inverse sine of ``x``."""
+ ...
+
+def atan(x: float) -> float:
+ """Return the inverse tangent of ``x``."""
+ ...
+
+def atan2(y: float, x: float) -> float:
+ """Return the principal value of the inverse tangent of ``y/x``."""
+ ...
+
+def ceil(x: float) -> int:
+ """Return an integer, being ``x`` rounded towards positive infinity."""
+ ...
+
+def copysign(x: float, y: float) -> float:
+ """Return ``x`` with the sign of ``y``."""
+ ...
+
+def cos(x: float) -> float:
+ """Return the cosine of ``x``."""
+ ...
+
+def degrees(x: float) -> float:
+ """Return radians ``x`` converted to degrees."""
+ ...
+
+def exp(x: float) -> float:
+ """Return the exponential of ``x``."""
+ ...
+
+def fabs(x: float) -> float:
+ """Return the absolute value of ``x``."""
+ ...
+
+def floor(x: float) -> int:
+ """Return an integer, being ``x`` rounded towards negative infinity."""
+ ...
+
+def fmod(x: float, y: float) -> int:
+ """Return the remainder of ``x/y``."""
+ ...
+
+def frexp(x: float) -> Tuple[int, int]:
+ """Decomposes a floating-point number into its mantissa and exponent.
+ The returned value is the tuple ``(m, e)`` such that ``x == m * 2**e``
+ exactly. If ``x == 0`` then the function returns ``(0.0, 0)``, otherwise
+ the relation ``0.5 <= abs(m) < 1`` holds."""
+ ...
+
+def isfinite(x: float) -> bool:
+ """Return ``True`` if ``x`` is finite."""
+ ...
+
+def isinf(x: float) -> bool:
+ """Return ``True`` if ``x`` is infinite."""
+ ...
+
+def isnan(x: float) -> bool:
+ """Return ``True`` if ``x`` is not-a-number"""
+ ...
+
+def ldexp(x: float, exp: float) -> float:
+ """Return ``x * (2**exp)``."""
+ ...
+
+def modf(x: float) -> Tuple[float, float]:
+ """Return a tuple of two floats, being the fractional and integral parts of
+ ``x``. Both return values have the same sign as ``x``."""
+ ...
+
+def pow(x: float, y: float) -> float:
+ """Returns ``x`` to the power of ``y``."""
+
+def radians(x: float) -> float:
+ """Return degrees ``x`` converted to radians."""
+
+def sin(x: float) -> float:
+ """Return the sine of ``x``."""
+ ...
+
+def sqrt(x: float) -> float:
+ """Returns the square root of ``x``."""
+ ...
+
+def tan(x: float) -> float:
+ """Return the tangent of ``x``."""
+ ...
+
+def trunc(x: float) -> int:
+ """Return an integer, being ``x`` rounded towards 0."""
+ ...
+
+def expm1(x: float) -> float:
+ """Return ``exp(x) - 1``."""
+ ...
+
+def log2(x: float) -> float:
+ """Return the base-2 logarithm of ``x``."""
+ ...
+
+def log10(x: float) -> float:
+ """Return the base-10 logarithm of ``x``."""
+ ...
+
+def cosh(x: float) -> float:
+ """Return the hyperbolic cosine of ``x``."""
+ ...
+
+def sinh(x: float) -> float:
+ """Return the hyperbolic sine of ``x``."""
+ ...
+
+def tanh(x: float) -> float:
+ """Return the hyperbolic tangent of ``x``."""
+ ...
+
+def acosh(x: float) -> float:
+ """Return the inverse hyperbolic cosine of ``x``."""
+ ...
+
+def asinh(x: float) -> float:
+ """Return the inverse hyperbolic sine of ``x``."""
+ ...
+
+def atanh(x: float) -> float:
+ """Return the inverse hyperbolic tangent of ``x``."""
+ ...
+
+def erf(x: float) -> float:
+ """Return the error function of ``x``."""
+ ...
+
+def erfc(x: float) -> float:
+ """Return the complementary error function of ``x``."""
+ ...
+
+def gamma(x: float) -> float:
+ """Return the gamma function of ``x``."""
+ ...
+
+def lgamma(x: float) -> float:
+ """Return the natural logarithm of the gamma function of ``x``."""
+ ...
diff --git a/stubs/memorymonitor/__init__.pyi b/stubs/memorymonitor/__init__.pyi
new file mode 100644
index 0000000..f49af1d
--- /dev/null
+++ b/stubs/memorymonitor/__init__.pyi
@@ -0,0 +1,104 @@
+"""Memory monitoring helpers"""
+
+from __future__ import annotations
+
+from typing import Optional
+
+class AllocationError(Exception):
+ """Catchall exception for allocation related errors."""
+
+ ...
+
+class AllocationAlarm:
+ def __init__(self, *, minimum_block_count: int = 1) -> None:
+ """Throw an exception when an allocation of ``minimum_block_count`` or more blocks
+ occurs while active.
+
+ Track allocations::
+
+ import memorymonitor
+
+ aa = memorymonitor.AllocationAlarm(minimum_block_count=2)
+ x = 2
+ # Should not allocate any blocks.
+ with aa:
+ x = 5
+
+ # Should throw an exception when allocating storage for the 20 bytes.
+ with aa:
+ x = bytearray(20)
+
+ """
+ ...
+ def ignore(self, count: int) -> AllocationAlarm:
+ """Sets the number of applicable allocations to ignore before raising the exception.
+ Automatically set back to zero at context exit.
+
+ Use it within a ``with`` block::
+
+ # Will not alarm because the bytearray allocation will be ignored.
+ with aa.ignore(2):
+ x = bytearray(20)
+ """
+ ...
+ def __enter__(self) -> AllocationAlarm:
+ """Enables the alarm."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically disables the allocation alarm when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+
+class AllocationSize:
+ def __init__(self) -> None:
+ """Tracks the number of allocations in power of two buckets.
+
+ It will have 16 16-bit buckets to track allocation counts. It is total allocations
+ meaning frees are ignored. Reallocated memory is counted twice, at allocation and when
+ reallocated with the larger size.
+
+ The buckets are measured in terms of blocks which is the finest granularity of the heap.
+ This means bucket 0 will count all allocations less than or equal to the number of bytes
+ per block, typically 16. Bucket 2 will be less than or equal to 4 blocks. See
+ `bytes_per_block` to convert blocks to bytes.
+
+ Multiple AllocationSizes can be used to track different code boundaries.
+
+ Track allocations::
+
+ import memorymonitor
+
+ mm = memorymonitor.AllocationSize()
+ with mm:
+ print("hello world" * 3)
+
+ for bucket, count in enumerate(mm):
+ print("<", 2 ** bucket, count)
+
+ """
+ ...
+ def __enter__(self) -> AllocationSize:
+ """Clears counts and resumes tracking."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically pauses allocation tracking when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ bytes_per_block: int
+ """Number of bytes per block"""
+ def __len__(self) -> int:
+ """Returns the number of allocation buckets.
+
+ This allows you to::
+
+ mm = memorymonitor.AllocationSize()
+ print(len(mm))"""
+ ...
+ def __getitem__(self, index: int) -> Optional[int]:
+ """Returns the allocation count for the given bucket.
+
+ This allows you to::
+
+ mm = memorymonitor.AllocationSize()
+ print(mm[0])"""
+ ...
diff --git a/stubs/microcontroller/__init__.pyi b/stubs/microcontroller/__init__.pyi
new file mode 100644
index 0000000..3f46502
--- /dev/null
+++ b/stubs/microcontroller/__init__.pyi
@@ -0,0 +1,147 @@
+"""Pin references and cpu functionality
+
+The `microcontroller` module defines the pins from the perspective of the
+microcontroller. See `board` for board-specific pin mappings."""
+
+from __future__ import annotations
+
+from typing import Optional
+
+import microcontroller
+from nvm import ByteArray
+from watchdog import WatchDogTimer
+
+cpu: Processor
+"""CPU information and control, such as ``cpu.temperature`` and ``cpu.frequency``
+(clock frequency).
+This object is the sole instance of `microcontroller.Processor`."""
+
+def delay_us(delay: int) -> None:
+ """Dedicated delay method used for very short delays. **Do not** do long delays
+ because this stops all other functions from completing. Think of this as an empty
+ ``while`` loop that runs for the specified ``(delay)`` time. If you have other
+ code or peripherals (e.g audio recording) that require specific timing or
+ processing while you are waiting, explore a different avenue such as using
+ `time.sleep()`."""
+ ...
+
+def disable_interrupts() -> None:
+ """Disable all interrupts. Be very careful, this can stall everything."""
+ ...
+
+def enable_interrupts() -> None:
+ """Enable the interrupts that were enabled at the last disable."""
+ ...
+
+def on_next_reset(run_mode: microcontroller.RunMode) -> None:
+ """Configure the run mode used the next time the microcontroller is reset but
+ not powered down.
+
+ :param ~microcontroller.RunMode run_mode: The next run mode"""
+ ...
+
+def reset() -> None:
+ """Reset the microcontroller. After reset, the microcontroller will enter the
+ run mode last set by `on_next_reset`.
+
+ .. warning:: This may result in file system corruption when connected to a
+ host computer. Be very careful when calling this! Make sure the device
+ "Safely removed" on Windows or "ejected" on Mac OSX and Linux."""
+ ...
+
+nvm: Optional[ByteArray]
+"""Available non-volatile memory.
+This object is the sole instance of `nvm.ByteArray` when available or ``None`` otherwise.
+
+:type: nvm.ByteArray or None"""
+
+watchdog: Optional[WatchDogTimer]
+"""Available watchdog timer.
+This object is the sole instance of `watchdog.WatchDogTimer` when available or ``None`` otherwise."""
+
+class Pin:
+ """Identifies an IO pin on the microcontroller."""
+
+ def __init__(self) -> None:
+ """Identifies an IO pin on the microcontroller. They are fixed by the
+ hardware so they cannot be constructed on demand. Instead, use
+ :mod:`board` or :mod:`microcontroller.pin` to reference the desired pin."""
+ ...
+
+class Processor:
+ """Microcontroller CPU information and control
+
+ Usage::
+
+ import microcontroller
+ print(microcontroller.cpu.frequency)
+ print(microcontroller.cpu.temperature)"""
+
+ def __init__(self) -> None:
+ """You cannot create an instance of `microcontroller.Processor`.
+ Use `microcontroller.cpu` to access the sole instance available."""
+ ...
+ frequency: int
+ """The CPU operating frequency in Hertz. (read-only)"""
+
+ reset_reason: microcontroller.ResetReason
+ """The reason the microcontroller started up from reset state."""
+
+ temperature: Optional[float]
+ """The on-chip temperature, in Celsius, as a float. (read-only)
+
+ Is `None` if the temperature is not available."""
+
+ uid: bytearray
+ """The unique id (aka serial number) of the chip as a `bytearray`. (read-only)"""
+
+ voltage: Optional[float]
+ """The input voltage to the microcontroller, as a float. (read-only)
+
+ Is `None` if the voltage is not available."""
+
+class ResetReason:
+ """The reason the microntroller was last reset"""
+
+ POWER_ON: object
+ """The microntroller was started from power off."""
+
+ BROWNOUT: object
+ """The microntroller was reset due to too low a voltage."""
+
+ SOFTWARE: object
+ """The microntroller was reset from software."""
+
+ DEEP_SLEEP_ALARM: object
+ """The microntroller was reset for deep sleep and restarted by an alarm."""
+
+ RESET_PIN: object
+ """The microntroller was reset by a signal on its reset pin. The pin might be connected to a reset button."""
+
+ WATCHDOG: object
+ """The microcontroller was reset by its watchdog timer."""
+
+ UNKNOWN: object
+ """The microntroller restarted for an unknown reason."""
+
+class RunMode:
+ """run state of the microcontroller"""
+
+ def __init__(self) -> None:
+ """Enum-like class to define the run mode of the microcontroller and
+ CircuitPython."""
+ NORMAL: RunMode
+ """Run CircuitPython as normal.
+
+ :type microcontroller.RunMode:"""
+
+ SAFE_MODE: RunMode
+ """Run CircuitPython in safe mode. User code will not be run and the
+ file system will be writeable over USB.
+
+ :type microcontroller.RunMode:"""
+
+ BOOTLOADER: RunMode
+ """Run the bootloader.
+
+ :type microcontroller.RunMode:"""
diff --git a/stubs/multiterminal/__init__.pyi b/stubs/multiterminal/__init__.pyi
new file mode 100644
index 0000000..0e4de7b
--- /dev/null
+++ b/stubs/multiterminal/__init__.pyi
@@ -0,0 +1,33 @@
+"""Manage additional terminal sources
+
+The `multiterminal` module allows you to configure an additional serial
+terminal source. Incoming characters are accepted from both the internal
+serial connection and the optional secondary connection."""
+
+from __future__ import annotations
+
+import socket
+import typing
+from typing import Optional
+
+def get_secondary_terminal() -> Optional[typing.BinaryIO]:
+ """Returns the current secondary terminal."""
+ ...
+
+def set_secondary_terminal(stream: typing.BinaryIO) -> None:
+ """Read additional input from the given stream and write out back to it.
+ This doesn't replace the core stream (usually UART or native USB) but is
+ mixed in instead.
+
+ :param stream stream: secondary stream"""
+ ...
+
+def clear_secondary_terminal() -> None:
+ """Clears the secondary terminal."""
+ ...
+
+def schedule_secondary_terminal_read(socket: socket.socket) -> None:
+ """In cases where the underlying OS is doing task scheduling, this notifies
+ the OS when more data is available on the socket to read. This is useful
+ as a callback for lwip sockets."""
+ ...
diff --git a/stubs/neopixel_write/__init__.pyi b/stubs/neopixel_write/__init__.pyi
new file mode 100644
index 0000000..15da1f6
--- /dev/null
+++ b/stubs/neopixel_write/__init__.pyi
@@ -0,0 +1,30 @@
+"""Low-level neopixel implementation
+
+The `neopixel_write` module contains a helper method to write out bytes in
+the 800khz neopixel protocol.
+
+For example, to turn off a single neopixel (like the status pixel on Express
+boards.)
+
+.. code-block:: python
+
+ import board
+ import neopixel_write
+ import digitalio
+
+ pin = digitalio.DigitalInOut(board.NEOPIXEL)
+ pin.direction = digitalio.Direction.OUTPUT
+ pixel_off = bytearray([0, 0, 0])
+ neopixel_write.neopixel_write(pin, pixel_off)"""
+
+from __future__ import annotations
+
+import digitalio
+from _typing import ReadableBuffer
+
+def neopixel_write(digitalinout: digitalio.DigitalInOut, buf: ReadableBuffer) -> None:
+ """Write buf out on the given DigitalInOut.
+
+ :param ~digitalio.DigitalInOut digitalinout: the DigitalInOut to output with
+ :param ~_typing.ReadableBuffer buf: The bytes to clock out. No assumption is made about color order"""
+ ...
diff --git a/stubs/network/__init__.pyi b/stubs/network/__init__.pyi
new file mode 100644
index 0000000..749fc33
--- /dev/null
+++ b/stubs/network/__init__.pyi
@@ -0,0 +1,16 @@
+"""Network Interface Management
+
+.. warning:: This module is disabled in 6.x and will removed in 7.x. Please use networking
+ libraries instead.
+
+This module provides a registry of configured NICs.
+It is used by the 'socket' module to look up a suitable
+NIC when a socket is created."""
+
+from __future__ import annotations
+
+from typing import List
+
+def route() -> List[object]:
+ """Returns a list of all configured NICs."""
+ ...
diff --git a/stubs/nvm/__init__.pyi b/stubs/nvm/__init__.pyi
new file mode 100644
index 0000000..f99e6ff
--- /dev/null
+++ b/stubs/nvm/__init__.pyi
@@ -0,0 +1,45 @@
+"""Non-volatile memory
+
+The `nvm` module allows you to store whatever raw bytes you wish in a
+reserved section non-volatile memory.
+
+Note that this module can't be imported and used directly. The sole
+instance of :class:`ByteArray` is available at
+:attr:`microcontroller.nvm`."""
+
+from __future__ import annotations
+
+from typing import overload
+
+from _typing import ReadableBuffer
+
+class ByteArray:
+ r"""Presents a stretch of non-volatile memory as a bytearray.
+
+ Non-volatile memory is available as a byte array that persists over reloads
+ and power cycles. Each assignment causes an erase and write cycle so its recommended to assign
+ all values to change at once.
+
+ Usage::
+
+ import microcontroller
+ microcontroller.nvm[0:3] = b\"\xcc\x10\x00\" """
+ def __init__(self) -> None:
+ """Not currently dynamically supported. Access the sole instance through `microcontroller.nvm`."""
+ ...
+ def __bool__(self) -> bool: ...
+ def __len__(self) -> int:
+ """Return the length. This is used by (`len`)"""
+ ...
+ @overload
+ def __getitem__(self, index: slice) -> bytearray: ...
+ @overload
+ def __getitem__(self, index: int) -> int:
+ """Returns the value at the given index."""
+ ...
+ @overload
+ def __setitem__(self, index: slice, value: ReadableBuffer) -> None: ...
+ @overload
+ def __setitem__(self, index: int, value: int) -> None:
+ """Set the value at the given index."""
+ ...
diff --git a/stubs/os/__init__.pyi b/stubs/os/__init__.pyi
new file mode 100644
index 0000000..4de2ca3
--- /dev/null
+++ b/stubs/os/__init__.pyi
@@ -0,0 +1,94 @@
+"""functions that an OS normally provides
+
+The `os` module is a strict subset of the CPython `cpython:os` module. So,
+code written in CircuitPython will work in CPython but not necessarily the
+other way around."""
+
+from __future__ import annotations
+
+import typing
+from typing import Tuple
+
+def uname() -> _Uname:
+ """Returns a named tuple of operating specific and CircuitPython port
+ specific information."""
+ ...
+
+class _Uname(typing.NamedTuple):
+ """The type of values that :py:func:`.uname()` returns"""
+
+ sysname: str
+ nodename: str
+ release: str
+ version: str
+ machine: str
+
+def chdir(path: str) -> None:
+ """Change current directory."""
+ ...
+
+def getcwd() -> str:
+ """Get the current directory."""
+ ...
+
+def listdir(dir: str) -> str:
+ """With no argument, list the current directory. Otherwise list the given directory."""
+ ...
+
+def mkdir(path: str) -> None:
+ """Create a new directory."""
+ ...
+
+def remove(path: str) -> None:
+ """Remove a file."""
+ ...
+
+def rmdir(path: str) -> None:
+ """Remove a directory."""
+ ...
+
+def rename(old_path: str, new_path: str) -> str:
+ """Rename a file."""
+ ...
+
+def stat(path: str) -> Tuple[int, int, int, int, int, int, int, int, int, int]:
+ """Get the status of a file or directory.
+
+ .. note:: On builds without long integers, the number of seconds
+ for contemporary dates will not fit in a small integer.
+ So the time fields return 946684800,
+ which is the number of seconds corresponding to 1999-12-31."""
+ ...
+
+def statvfs(path: str) -> Tuple[int, int, int, int, int, int, int, int, int, int]:
+ """Get the status of a filesystem.
+
+ Returns a tuple with the filesystem information in the following order:
+
+ * ``f_bsize`` -- file system block size
+ * ``f_frsize`` -- fragment size
+ * ``f_blocks`` -- size of fs in f_frsize units
+ * ``f_bfree`` -- number of free blocks
+ * ``f_bavail`` -- number of free blocks for unprivileged users
+ * ``f_files`` -- number of inodes
+ * ``f_ffree`` -- number of free inodes
+ * ``f_favail`` -- number of free inodes for unprivileged users
+ * ``f_flag`` -- mount flags
+ * ``f_namemax`` -- maximum filename length
+
+ Parameters related to inodes: ``f_files``, ``f_ffree``, ``f_avail``
+ and the ``f_flags`` parameter may return ``0`` as they can be unavailable
+ in a port-specific implementation."""
+ ...
+
+def sync() -> None:
+ """Sync all filesystems."""
+ ...
+
+def urandom(size: int) -> str:
+ """Returns a string of *size* random bytes based on a hardware True Random
+ Number Generator. When not available, it will raise a NotImplementedError."""
+ ...
+
+sep: str
+"""Separator used to delineate path components such as folder and file names."""
diff --git a/stubs/ps2io/__init__.pyi b/stubs/ps2io/__init__.pyi
new file mode 100644
index 0000000..133f98b
--- /dev/null
+++ b/stubs/ps2io/__init__.pyi
@@ -0,0 +1,108 @@
+"""Support for PS/2 protocol
+
+The `ps2io` module contains classes to provide PS/2 communication.
+
+.. warning:: This module is not available in some SAMD21 builds. See the
+ :ref:`module-support-matrix` for more info.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info."""
+
+from __future__ import annotations
+
+import microcontroller
+
+class Ps2:
+ """Communicate with a PS/2 keyboard or mouse
+
+ Ps2 implements the PS/2 keyboard/mouse serial protocol, used in
+ legacy devices. It is similar to UART but there are only two
+ lines (Data and Clock). PS/2 devices are 5V, so bidirectional
+ level converters must be used to connect the I/O lines to pins
+ of 3.3V boards."""
+
+ def __init__(
+ self, data_pin: microcontroller.Pin, clock_pin: microcontroller.Pin
+ ) -> None:
+ """Create a Ps2 object associated with the given pins.
+
+ :param ~microcontroller.Pin data_pin: Pin tied to data wire.
+ :param ~microcontroller.Pin clock_pin: Pin tied to clock wire.
+ This pin must support interrupts.
+
+ Read one byte from PS/2 keyboard and turn on Scroll Lock LED::
+
+ import ps2io
+ import board
+
+ kbd = ps2io.Ps2(board.D10, board.D11)
+
+ while len(kbd) == 0:
+ pass
+
+ print(kbd.popleft())
+ print(kbd.sendcmd(0xed))
+ print(kbd.sendcmd(0x01))"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the Ps2 and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> Ps2:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def popleft(self) -> int:
+ """Removes and returns the oldest received byte. When buffer
+ is empty, raises an IndexError exception."""
+ ...
+ def sendcmd(self, byte: int) -> int:
+ """Sends a command byte to PS/2. Returns the response byte, typically
+ the general ack value (0xFA). Some commands return additional data
+ which is available through :py:func:`popleft()`.
+
+ Raises a RuntimeError in case of failure. The root cause can be found
+ by calling :py:func:`clear_errors()`. It is advisable to call
+ :py:func:`clear_errors()` before :py:func:`sendcmd()` to flush any
+ previous errors.
+
+ :param int byte: byte value of the command"""
+ ...
+ def clear_errors(self) -> None:
+ """Returns and clears a bitmap with latest recorded communication errors.
+
+ Reception errors (arise asynchronously, as data is received):
+
+ 0x01: start bit not 0
+
+ 0x02: timeout
+
+ 0x04: parity bit error
+
+ 0x08: stop bit not 1
+
+ 0x10: buffer overflow, newest data discarded
+
+ Transmission errors (can only arise in the course of sendcmd()):
+
+ 0x100: clock pin didn't go to LO in time
+
+ 0x200: clock pin didn't go to HI in time
+
+ 0x400: data pin didn't ACK
+
+ 0x800: clock pin didn't ACK
+
+ 0x1000: device didn't respond to RTS
+
+ 0x2000: device didn't send a response byte in time"""
+ ...
+ def __bool__(self) -> bool: ...
+ def __len__(self) -> int:
+ """Returns the number of received bytes in buffer, available
+ to :py:func:`popleft()`."""
+ ...
diff --git a/stubs/pulseio/__init__.pyi b/stubs/pulseio/__init__.pyi
new file mode 100644
index 0000000..df4ea7f
--- /dev/null
+++ b/stubs/pulseio/__init__.pyi
@@ -0,0 +1,167 @@
+"""Support for individual pulse based protocols
+
+The `pulseio` module contains classes to provide access to basic pulse IO.
+Individual pulses are commonly used in infrared remotes and in DHT
+temperature sensors.
+
+
+.. warning:: PWMOut is moving to `pwmio` and will be removed from `pulseio`
+ in CircuitPython 7.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info."""
+
+from __future__ import annotations
+
+from typing import Optional
+
+import microcontroller
+import pwmio
+from _typing import ReadableBuffer
+
+class PulseIn:
+ """Measure a series of active and idle pulses. This is commonly used in infrared receivers
+ and low cost temperature sensors (DHT). The pulsed signal consists of timed active and
+ idle periods. Unlike PWM, there is no set duration for active and idle pairs."""
+
+ def __init__(
+ self, pin: microcontroller.Pin, maxlen: int = 2, *, idle_state: bool = False
+ ) -> None:
+ """Create a PulseIn object associated with the given pin. The object acts as
+ a read-only sequence of pulse lengths with a given max length. When it is
+ active, new pulse lengths are added to the end of the list. When there is
+ no more room (len() == `maxlen`) the oldest pulse length is removed to
+ make room.
+
+ :param ~microcontroller.Pin pin: Pin to read pulses from.
+ :param int maxlen: Maximum number of pulse durations to store at once
+ :param bool idle_state: Idle state of the pin. At start and after `resume`
+ the first recorded pulse will the opposite state from idle.
+
+ Read a short series of pulses::
+
+ import pulseio
+ import board
+
+ pulses = pulseio.PulseIn(board.D7)
+
+ # Wait for an active pulse
+ while len(pulses) == 0:
+ pass
+ # Pause while we do something with the pulses
+ pulses.pause()
+
+ # Print the pulses. pulses[0] is an active pulse unless the length
+ # reached max length and idle pulses are recorded.
+ print(pulses)
+
+ # Clear the rest
+ pulses.clear()
+
+ # Resume with an 80 microsecond active pulse
+ pulses.resume(80)"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the PulseIn and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> PulseIn:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def pause(self) -> None:
+ """Pause pulse capture"""
+ ...
+ def resume(self, trigger_duration: int = 0) -> None:
+ """Resumes pulse capture after an optional trigger pulse.
+
+ .. warning:: Using trigger pulse with a device that drives both high and
+ low signals risks a short. Make sure your device is open drain (only
+ drives low) when using a trigger pulse. You most likely added a
+ "pull-up" resistor to your circuit to do this.
+
+ :param int trigger_duration: trigger pulse duration in microseconds"""
+ ...
+ def clear(self) -> None:
+ """Clears all captured pulses"""
+ ...
+ def popleft(self) -> int:
+ """Removes and returns the oldest read pulse."""
+ ...
+ maxlen: int
+ """The maximum length of the PulseIn. When len() is equal to maxlen,
+ it is unclear which pulses are active and which are idle."""
+
+ paused: bool
+ """True when pulse capture is paused as a result of :py:func:`pause` or an error during capture
+ such as a signal that is too fast."""
+ def __bool__(self) -> bool: ...
+ def __len__(self) -> int:
+ """Returns the current pulse length
+
+ This allows you to::
+
+ pulses = pulseio.PulseIn(pin)
+ print(len(pulses))"""
+ ...
+ def __getitem__(self, index: int) -> Optional[int]:
+ """Returns the value at the given index or values in slice.
+
+ This allows you to::
+
+ pulses = pulseio.PulseIn(pin)
+ print(pulses[0])"""
+ ...
+
+class PulseOut:
+ """Pulse PWM "carrier" output on and off. This is commonly used in infrared remotes. The
+ pulsed signal consists of timed on and off periods. Unlike PWM, there is no set duration
+ for on and off pairs."""
+
+ def __init__(self, carrier: pwmio.PWMOut) -> None:
+ """Create a PulseOut object associated with the given PWMout object.
+
+ :param ~pwmio.PWMOut carrier: PWMOut that is set to output on the desired pin.
+
+ Send a short series of pulses::
+
+ import array
+ import pulseio
+ import pwmio
+ import board
+
+ # 50% duty cycle at 38kHz.
+ pwm = pwmio.PWMOut(board.D13, frequency=38000, duty_cycle=32768)
+ pulse = pulseio.PulseOut(pwm)
+ # on off on off on
+ pulses = array.array('H', [65000, 1000, 65000, 65000, 1000])
+ pulse.send(pulses)
+
+ # Modify the array of pulses.
+ pulses[0] = 200
+ pulse.send(pulses)"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the PulseOut and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> PulseOut:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def send(self, pulses: ReadableBuffer) -> None:
+ """Pulse alternating on and off durations in microseconds starting with on.
+ ``pulses`` must be an `array.array` with data type 'H' for unsigned
+ halfword (two bytes).
+
+ This method waits until the whole array of pulses has been sent and
+ ensures the signal is off afterwards.
+
+ :param array.array pulses: pulse durations in microseconds"""
+ ...
diff --git a/stubs/pwmio/__init__.pyi b/stubs/pwmio/__init__.pyi
new file mode 100644
index 0000000..b359b20
--- /dev/null
+++ b/stubs/pwmio/__init__.pyi
@@ -0,0 +1,110 @@
+"""Support for PWM based protocols
+
+The `pwmio` module contains classes to provide access to basic pulse IO.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+For example::
+
+ import pwmio
+ import time
+ from board import *
+
+ pwm = pwmio.PWMOut(D13)
+ pwm.duty_cycle = 2 ** 15
+ time.sleep(0.1)
+
+This example will initialize the the device, set
+:py:data:`~pwmio.PWMOut.duty_cycle`, and then sleep 0.1 seconds.
+CircuitPython will automatically turn off the PWM when it resets all
+hardware after program completion. Use ``deinit()`` or a ``with`` statement
+to do it yourself."""
+
+from __future__ import annotations
+
+import microcontroller
+
+class PWMOut:
+ """Output a Pulse Width Modulated signal on a given pin."""
+
+ def __init__(
+ self,
+ pin: microcontroller.Pin,
+ *,
+ duty_cycle: int = 0,
+ frequency: int = 500,
+ variable_frequency: bool = False
+ ) -> None:
+ """Create a PWM object associated with the given pin. This allows you to
+ write PWM signals out on the given pin. Frequency is fixed after init
+ unless ``variable_frequency`` is True.
+
+ .. note:: When ``variable_frequency`` is True, further PWM outputs may be
+ limited because it may take more internal resources to be flexible. So,
+ when outputting both fixed and flexible frequency signals construct the
+ fixed outputs first.
+
+ :param ~microcontroller.Pin pin: The pin to output to
+ :param int duty_cycle: The fraction of each pulse which is high. 16-bit
+ :param int frequency: The target frequency in Hertz (32-bit)
+ :param bool variable_frequency: True if the frequency will change over time
+
+ Simple LED fade::
+
+ import pwmio
+ import board
+
+ pwm = pwmio.PWMOut(board.D13) # output on D13
+ pwm.duty_cycle = 2 ** 15 # Cycles the pin with 50% duty cycle (half of 2 ** 16) at the default 500hz
+
+ PWM at specific frequency (servos and motors)::
+
+ import pwmio
+ import board
+
+ pwm = pwmio.PWMOut(board.D13, frequency=50)
+ pwm.duty_cycle = 2 ** 15 # Cycles the pin with 50% duty cycle (half of 2 ** 16) at 50hz
+
+ Variable frequency (usually tones)::
+
+ import pwmio
+ import board
+ import time
+
+ pwm = pwmio.PWMOut(board.D13, duty_cycle=2 ** 15, frequency=440, variable_frequency=True)
+ time.sleep(0.2)
+ pwm.frequency = 880
+ time.sleep(0.1)"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the PWMOut and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> PWMOut:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ duty_cycle: int
+ """16 bit value that dictates how much of one cycle is high (1) versus low
+ (0). 0xffff will always be high, 0 will always be low and 0x7fff will
+ be half high and then half low.
+
+ Depending on how PWM is implemented on a specific board, the internal
+ representation for duty cycle might have less than 16 bits of resolution.
+ Reading this property will return the value from the internal representation,
+ so it may differ from the value set."""
+
+ frequency: int
+ """32 bit value that dictates the PWM frequency in Hertz (cycles per
+ second). Only writeable when constructed with ``variable_frequency=True``.
+
+ Depending on how PWM is implemented on a specific board, the internal value
+ for the PWM's duty cycle may need to be recalculated when the frequency
+ changes. In these cases, the duty cycle is automatically recalculated
+ from the original duty cycle value. This should happen without any need
+ to manually re-set the duty cycle."""
diff --git a/stubs/random/__init__.pyi b/stubs/random/__init__.pyi
new file mode 100644
index 0000000..b810e20
--- /dev/null
+++ b/stubs/random/__init__.pyi
@@ -0,0 +1,50 @@
+"""pseudo-random numbers and choices
+
+The `random` module is a strict subset of the CPython `cpython:random`
+module. So, code written in CircuitPython will work in CPython but not
+necessarily the other way around.
+
+Like its CPython cousin, CircuitPython's random seeds itself on first use
+with a true random from os.urandom() when available or the uptime otherwise.
+Once seeded, it will be deterministic, which is why its bad for cryptography.
+
+.. warning:: Numbers from this module are not cryptographically strong! Use
+ bytes from `os.urandom` directly for true randomness."""
+
+from __future__ import annotations
+
+from typing import Sequence, Tuple, TypeVar
+
+_T = TypeVar("_T")
+
+def seed(seed: int) -> None:
+ """Sets the starting seed of the random number generation. Further calls to
+ `random` will return deterministic results afterwards."""
+ ...
+
+def getrandbits(k: int) -> int:
+ """Returns an integer with *k* random bits."""
+ ...
+
+def randrange(stop: Tuple[int, int, int]) -> int:
+ """Returns a randomly selected integer from ``range(start, stop, step)``."""
+ ...
+
+def randint(a: int, b: int) -> int:
+ """Returns a randomly selected integer between a and b inclusive. Equivalent
+ to ``randrange(a, b + 1, 1)``"""
+ ...
+
+def choice(seq: Sequence[_T]) -> _T:
+ """Returns a randomly selected element from the given sequence. Raises
+ IndexError when the sequence is empty."""
+ ...
+
+def random() -> float:
+ """Returns a random float between 0 and 1.0."""
+ ...
+
+def uniform(a: float, b: float) -> float:
+ """Returns a random float between a and b. It may or may not be inclusive
+ depending on float rounding."""
+ ...
diff --git a/stubs/rgbmatrix/__init__.pyi b/stubs/rgbmatrix/__init__.pyi
new file mode 100644
index 0000000..8ae9857
--- /dev/null
+++ b/stubs/rgbmatrix/__init__.pyi
@@ -0,0 +1,78 @@
+"""Low-level routines for bitbanged LED matrices"""
+
+from __future__ import annotations
+
+from typing import Optional, Sequence
+
+import digitalio
+from _typing import WriteableBuffer
+
+class RGBMatrix:
+ """Displays an in-memory framebuffer to a HUB75-style RGB LED matrix."""
+
+ def __init__(
+ self,
+ *,
+ width: int,
+ bit_depth: int,
+ rgb_pins: Sequence[digitalio.DigitalInOut],
+ addr_pins: Sequence[digitalio.DigitalInOut],
+ clock_pin: digitalio.DigitalInOut,
+ latch_pin: digitalio.DigitalInOut,
+ output_enable_pin: digitalio.DigitalInOut,
+ doublebuffer: bool = True,
+ framebuffer: Optional[WriteableBuffer] = None,
+ height: int = 0
+ ) -> None:
+ """Create a RGBMatrix object with the given attributes. The height of
+ the display is determined by the number of rgb and address pins:
+ len(rgb_pins) // 3 * 2 ** len(address_pins). With 6 RGB pins and 4
+ address lines, the display will be 32 pixels tall. If the optional height
+ parameter is specified and is not 0, it is checked against the calculated
+ height.
+
+ Up to 30 RGB pins and 8 address pins are supported.
+
+ The RGB pins must be within a single "port" and performance and memory
+ usage are best when they are all within "close by" bits of the port.
+ The clock pin must also be on the same port as the RGB pins. See the
+ documentation of the underlying protomatter C library for more
+ information. Generally, Adafruit's interface boards are designed so
+ that these requirements are met when matched with the intended
+ microcontroller board. For instance, the Feather M4 Express works
+ together with the RGB Matrix Feather.
+
+ The framebuffer is in "RGB565" format.
+
+ "RGB565" means that it is organized as a series of 16-bit numbers
+ where the highest 5 bits are interpreted as red, the next 6 as
+ green, and the final 5 as blue. The object can be any buffer, but
+ `array.array` and `ulab.array` objects are most often useful.
+ To update the content, modify the framebuffer and call refresh.
+
+ If a framebuffer is not passed in, one is allocated and initialized
+ to all black. In any case, the framebuffer can be retrieved
+ by passing the RGBMatrix object to memoryview().
+
+ If doublebuffer is False, some memory is saved, but the display may
+ flicker during updates.
+
+ A RGBMatrix is often used in conjunction with a
+ `framebufferio.FramebufferDisplay`."""
+ def deinit(self) -> None:
+ """Free the resources (pins, timers, etc.) associated with this
+ rgbmatrix instance. After deinitialization, no further operations
+ may be performed."""
+ ...
+ brightness: float
+ """In the current implementation, 0.0 turns the display off entirely
+ and any other value up to 1.0 turns the display on fully."""
+ def refresh(self) -> None:
+ """Transmits the color data in the buffer to the pixels so that
+ they are shown."""
+ ...
+ width: int
+ """The width of the display, in pixels"""
+
+ height: int
+ """The height of the display, in pixels"""
diff --git a/stubs/rotaryio/__init__.pyi b/stubs/rotaryio/__init__.pyi
new file mode 100644
index 0000000..9fe8992
--- /dev/null
+++ b/stubs/rotaryio/__init__.pyi
@@ -0,0 +1,53 @@
+"""Support for reading rotation sensors
+
+The `rotaryio` module contains classes to read different rotation encoding schemes. See
+`Wikipedia's Rotary Encoder page `_ for more
+background.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info."""
+
+from __future__ import annotations
+
+import microcontroller
+
+class IncrementalEncoder:
+ """IncrementalEncoder determines the relative rotational position based on two series of pulses."""
+
+ def __init__(self, pin_a: microcontroller.Pin, pin_b: microcontroller.Pin) -> None:
+ """Create an IncrementalEncoder object associated with the given pins. It tracks the positional
+ state of an incremental rotary encoder (also known as a quadrature encoder.) Position is
+ relative to the position when the object is contructed.
+
+ :param ~microcontroller.Pin pin_a: First pin to read pulses from.
+ :param ~microcontroller.Pin pin_b: Second pin to read pulses from.
+
+ For example::
+
+ import rotaryio
+ import time
+ from board import *
+
+ enc = rotaryio.IncrementalEncoder(D1, D2)
+ last_position = None
+ while True:
+ position = enc.position
+ if last_position == None or position != last_position:
+ print(position)
+ last_position = position"""
+ ...
+ def deinit(self) -> None:
+ """Deinitializes the IncrementalEncoder and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> IncrementalEncoder:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ position: int
+ """The current position in terms of pulses. The number of pulses per rotation is defined by the
+ specific hardware."""
diff --git a/stubs/rtc/__init__.pyi b/stubs/rtc/__init__.pyi
new file mode 100644
index 0000000..da57494
--- /dev/null
+++ b/stubs/rtc/__init__.pyi
@@ -0,0 +1,57 @@
+"""Real Time Clock
+
+The `rtc` module provides support for a Real Time Clock. You can access and manage the
+RTC using :class:`rtc.RTC`. It also backs the :func:`time.time` and :func:`time.localtime`
+functions using the onboard RTC if present."""
+
+from __future__ import annotations
+
+import time
+
+def set_time_source(rtc: RTC) -> None:
+ """Sets the RTC time source used by :func:`time.localtime`.
+ The default is :class:`rtc.RTC`, but it's useful to use this to override the
+ time source for testing purposes. For example::
+
+ import rtc
+ import time
+
+ class RTC(object):
+ @property
+ def datetime(self):
+ return time.struct_time((2018, 3, 17, 21, 1, 47, 0, 0, 0))
+
+ r = RTC()
+ rtc.set_time_source(r)"""
+ ...
+
+class RTC:
+ """Real Time Clock"""
+
+ def __init__(self) -> None:
+ """This class represents the onboard Real Time Clock. It is a singleton and will always return the same instance."""
+ ...
+ datetime: time.struct_time
+ """The current date and time of the RTC as a `time.struct_time`.
+
+ This must be set to the current date and time whenever the board loses power::
+
+ import rtc
+ import time
+
+ r = rtc.RTC()
+ r.datetime = time.struct_time((2019, 5, 29, 15, 14, 15, 0, -1, -1))
+
+
+ Once set, the RTC will automatically update this value as time passes. You can read this
+ property to get a snapshot of the current time::
+
+ current_time = r.datetime
+ print(current_time)
+ # struct_time(tm_year=2019, tm_month=5, ...)"""
+
+ calibration: int
+ """The RTC calibration value as an `int`.
+
+ A positive value speeds up the clock and a negative value slows it down.
+ Range and value is hardware specific, but one step is often approximately 1 ppm."""
diff --git a/stubs/samd/__init__.pyi b/stubs/samd/__init__.pyi
new file mode 100644
index 0000000..2aebcee
--- /dev/null
+++ b/stubs/samd/__init__.pyi
@@ -0,0 +1,32 @@
+"""SAMD implementation settings"""
+
+from __future__ import annotations
+
+from typing import Union
+
+""":mod:`samd.clock` --- samd clock names
+--------------------------------------------------------
+
+.. module:: samd.clock
+ :synopsis: samd clock names
+ :platform: SAMD21
+
+References to clocks as named by the microcontroller"""
+
+class Clock:
+ """Identifies a clock on the microcontroller.
+
+ They are fixed by the hardware so they cannot be constructed on demand. Instead, use
+ ``samd.clock`` to reference the desired clock."""
+
+ enabled: bool
+ """Is the clock enabled? (read-only)"""
+
+ parent: Union[Clock, None]
+ """Clock parent. (read-only)"""
+
+ frequency: int
+ """Clock frequency in Herz. (read-only)"""
+
+ calibration: int
+ """Clock calibration. Not all clocks can be calibrated."""
diff --git a/stubs/sdcardio/__init__.pyi b/stubs/sdcardio/__init__.pyi
new file mode 100644
index 0000000..46ed756
--- /dev/null
+++ b/stubs/sdcardio/__init__.pyi
@@ -0,0 +1,69 @@
+"""Interface to an SD card via the SPI bus"""
+
+from __future__ import annotations
+
+import busio
+import microcontroller
+from _typing import ReadableBuffer, WriteableBuffer
+
+class SDCard:
+ """SD Card Block Interface
+
+ Controls an SD card over SPI. This built-in module has higher read
+ performance than the library adafruit_sdcard, but it is only compatible with
+ `busio.SPI`, not `bitbangio.SPI`. Usually an SDCard object is used
+ with ``storage.VfsFat`` to allow file I/O to an SD card."""
+
+ def __init__(
+ self, bus: busio.SPI, cs: microcontroller.Pin, baudrate: int = 8000000
+ ) -> None:
+ """Construct an SPI SD Card object with the given properties
+
+ :param busio.SPI spi: The SPI bus
+ :param microcontroller.Pin cs: The chip select connected to the card
+ :param int baudrate: The SPI data rate to use after card setup
+
+ Note that during detection and configuration, a hard-coded low baudrate is used.
+ Data transfers use the specified baurate (rounded down to one that is supported by
+ the microcontroller)
+
+ Example usage:
+
+ .. code-block:: python
+
+ import os
+
+ import board
+ import sdcardio
+ import storage
+
+ sd = sdcardio.SDCard(board.SPI(), board.SD_CS)
+ vfs = storage.VfsFat(sd)
+ storage.mount(vfs, '/sd')
+ os.listdir('/sd')"""
+ def count(self) -> int:
+ """Returns the total number of sectors
+
+ Due to technical limitations, this is a function and not a property.
+
+ :return: The number of 512-byte blocks, as a number"""
+ def deinit(self) -> None:
+ """Disable permanently.
+
+ :return: None"""
+ def readblocks(self, start_block: int, buf: WriteableBuffer) -> None:
+
+ """Read one or more blocks from the card
+
+ :param int start_block: The block to start reading from
+ :param ~_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512.
+
+ :return: None"""
+ def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None:
+
+ """Write one or more blocks to the card
+
+ :param int start_block: The block to start writing from
+ :param ~_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512.
+
+ :return: None"""
diff --git a/stubs/sdioio/__init__.pyi b/stubs/sdioio/__init__.pyi
new file mode 100644
index 0000000..bec84cc
--- /dev/null
+++ b/stubs/sdioio/__init__.pyi
@@ -0,0 +1,101 @@
+"""Interface to an SD card via the SDIO bus"""
+
+from __future__ import annotations
+
+from typing import Sequence
+
+import microcontroller
+from _typing import ReadableBuffer, WriteableBuffer
+
+class SDCard:
+ """SD Card Block Interface with SDIO
+
+ Controls an SD card over SDIO. SDIO is a parallel protocol designed
+ for SD cards. It uses a clock pin, a command pin, and 1 or 4
+ data pins. It can be operated at a high frequency such as
+ 25MHz. Usually an SDCard object is used with ``storage.VfsFat``
+ to allow file I/O to an SD card."""
+
+ def __init__(
+ self,
+ clock: microcontroller.Pin,
+ command: microcontroller.Pin,
+ data: Sequence[microcontroller.Pin],
+ frequency: int,
+ ) -> None:
+ """Construct an SDIO SD Card object with the given properties
+
+ :param ~microcontroller.Pin clock: the pin to use for the clock.
+ :param ~microcontroller.Pin command: the pin to use for the command.
+ :param data: A sequence of pins to use for data.
+ :param frequency: The frequency of the bus in Hz
+
+ Example usage:
+
+ .. code-block:: python
+
+ import os
+
+ import board
+ import sdioio
+ import storage
+
+ sd = sdioio.SDCard(
+ clock=board.SDIO_CLOCK,
+ command=board.SDIO_COMMAND,
+ data=board.SDIO_DATA,
+ frequency=25000000)
+ vfs = storage.VfsFat(sd)
+ storage.mount(vfs, '/sd')
+ os.listdir('/sd')"""
+ ...
+ def configure(self, frequency: int = 0, width: int = 0) -> None:
+ """Configures the SDIO bus.
+
+ :param int frequency: the desired clock rate in Hertz. The actual clock rate may be higher or lower due to the granularity of available clock settings. Check the `frequency` attribute for the actual clock rate.
+ :param int width: the number of data lines to use. Must be 1 or 4 and must also not exceed the number of data lines at construction
+
+ .. note:: Leaving a value unspecified or 0 means the current setting is kept"""
+ def count(self) -> int:
+ """Returns the total number of sectors
+
+ Due to technical limitations, this is a function and not a property.
+
+ :return: The number of 512-byte blocks, as a number"""
+ def readblocks(self, start_block: int, buf: WriteableBuffer) -> None:
+
+ """Read one or more blocks from the card
+
+ :param int start_block: The block to start reading from
+ :param ~_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512.
+
+ :return: None"""
+ def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None:
+
+ """Write one or more blocks to the card
+
+ :param int start_block: The block to start writing from
+ :param ~_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512.
+
+ :return: None"""
+ @property
+ def frequency(self) -> int:
+ """The actual SDIO bus frequency. This may not match the frequency
+ requested due to internal limitations."""
+ ...
+ @property
+ def width(self) -> int:
+ """The actual SDIO bus width, in bits"""
+ ...
+ def deinit(self) -> None:
+ """Disable permanently.
+
+ :return: None"""
+ def __enter__(self) -> SDCard:
+ """No-op used by Context Managers.
+ Provided by context manager helper."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
diff --git a/stubs/sharpdisplay/__init__.pyi b/stubs/sharpdisplay/__init__.pyi
new file mode 100644
index 0000000..846c0f3
--- /dev/null
+++ b/stubs/sharpdisplay/__init__.pyi
@@ -0,0 +1,3 @@
+"""Support for Sharp Memory Display framebuffers"""
+
+from __future__ import annotations
diff --git a/stubs/socket/__init__.pyi b/stubs/socket/__init__.pyi
new file mode 100644
index 0000000..182f883
--- /dev/null
+++ b/stubs/socket/__init__.pyi
@@ -0,0 +1,116 @@
+"""TCP, UDP and RAW socket support
+
+.. warning:: This module is disabled in 6.x and will removed in 7.x. Please use networking
+ libraries instead. (Native networking will provide a socket compatible class.)
+
+Create TCP, UDP and RAW sockets for communicating over the Internet."""
+
+from __future__ import annotations
+
+from typing import Optional, Tuple
+
+from _typing import ReadableBuffer, WriteableBuffer
+
+class socket:
+
+ AF_INET: int
+ AF_INET6: int
+ SOCK_STREAM: int
+ SOCK_DGRAM: int
+ SOCK_RAW: int
+ IPPROTO_TCP: int
+ def __init__(
+ self, family: int = AF_INET, type: int = SOCK_STREAM, proto: int = IPPROTO_TCP
+ ) -> None:
+ """Create a new socket
+
+ :param int family: AF_INET or AF_INET6
+ :param int type: SOCK_STREAM, SOCK_DGRAM or SOCK_RAW
+ :param int proto: IPPROTO_TCP, IPPROTO_UDP or IPPROTO_RAW (ignored)"""
+ ...
+ def bind(self, address: Tuple[str, int]) -> None:
+ """Bind a socket to an address
+
+ :param address: tuple of (remote_address, remote_port)
+ :type address: tuple(str, int)"""
+ ...
+ def listen(self, backlog: int) -> None:
+ """Set socket to listen for incoming connections
+
+ :param int backlog: length of backlog queue for waiting connetions"""
+ ...
+ def accept(self) -> Tuple[socket, str]:
+ """Accept a connection on a listening socket of type SOCK_STREAM,
+ creating a new socket of type SOCK_STREAM.
+ Returns a tuple of (new_socket, remote_address)"""
+ def connect(self, address: Tuple[str, int]) -> None:
+ """Connect a socket to a remote address
+
+ :param address: tuple of (remote_address, remote_port)
+ :type address: tuple(str, int)"""
+ ...
+ def send(self, bytes: ReadableBuffer) -> int:
+ """Send some bytes to the connected remote address.
+ Suits sockets of type SOCK_STREAM
+
+ :param ~_typing.ReadableBuffer bytes: some bytes to send"""
+ ...
+ def recv_into(self, buffer: WriteableBuffer, bufsize: int) -> int:
+ """Reads some bytes from the connected remote address, writing
+ into the provided buffer. If bufsize <= len(buffer) is given,
+ a maximum of bufsize bytes will be read into the buffer. If no
+ valid value is given for bufsize, the default is the length of
+ the given buffer.
+
+ Suits sockets of type SOCK_STREAM
+ Returns an int of number of bytes read.
+
+ :param ~_typing.WriteableBuffer buffer: buffer to receive into
+ :param int bufsize: optionally, a maximum number of bytes to read."""
+ ...
+ def recv(self, bufsize: int) -> bytes:
+ """Reads some bytes from the connected remote address.
+ Suits sockets of type SOCK_STREAM
+ Returns a bytes() of length <= bufsize
+
+ :param int bufsize: maximum number of bytes to receive"""
+ ...
+ def sendto(self, bytes: ReadableBuffer, address: Tuple[str, int]) -> int:
+ """Send some bytes to a specific address.
+ Suits sockets of type SOCK_DGRAM
+
+ :param ~_typing.ReadableBuffer bytes: some bytes to send
+ :param address: tuple of (remote_address, remote_port)
+ :type address: tuple(str, int)"""
+ ...
+ def recvfrom(self, bufsize: int) -> Tuple[bytes, Tuple[str, int]]:
+ """Reads some bytes from the connected remote address.
+ Suits sockets of type SOCK_STREAM
+
+ Returns a tuple containing
+ * a bytes() of length <= bufsize
+ * a remote_address, which is a tuple of ip address and port number
+
+ :param int bufsize: maximum number of bytes to receive"""
+ ...
+ def setsockopt(self, level: int, optname: int, value: int) -> None:
+ """Sets socket options"""
+ ...
+ def settimeout(self, value: int) -> None:
+ """Set the timeout value for this socket.
+
+ :param int value: timeout in seconds. 0 means non-blocking. None means block indefinitely."""
+ ...
+ def setblocking(self, flag: bool) -> Optional[int]:
+ """Set the blocking behaviour of this socket.
+
+ :param bool flag: False means non-blocking, True means block indefinitely."""
+ ...
+
+def getaddrinfo(host: str, port: int) -> Tuple[int, int, int, str, str]:
+ """Gets the address information for a hostname and port
+
+ Returns the appropriate family, socket type, socket protocol and
+ address information to call socket.socket() and socket.connect() with,
+ as a tuple."""
+ ...
diff --git a/stubs/socketpool/__init__.pyi b/stubs/socketpool/__init__.pyi
new file mode 100644
index 0000000..1f96a61
--- /dev/null
+++ b/stubs/socketpool/__init__.pyi
@@ -0,0 +1,109 @@
+"""
+The `socketpool` module provides sockets through a pool. The pools themselves
+act like CPython's `socket` module.
+"""
+
+from __future__ import annotations
+
+from typing import Tuple
+
+import socketpool
+from _typing import ReadableBuffer, WriteableBuffer
+
+class Socket:
+ """TCP, UDP and RAW socket. Cannot be created directly. Instead, call
+ `SocketPool.socket()`.
+
+ Provides a subset of CPython's `socket.socket` API. It only implements the versions of
+ recv that do not allocate bytes objects."""
+
+ def __enter__(self) -> Socket:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically closes the Socket when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ def close(self) -> None:
+ """Closes this Socket and makes its resources available to its SocketPool."""
+ def connect(self, address: Tuple[str, int]) -> None:
+ """Connect a socket to a remote address
+
+ :param ~tuple address: tuple of (remote_address, remote_port)"""
+ ...
+ def send(self, bytes: ReadableBuffer) -> int:
+ """Send some bytes to the connected remote address.
+ Suits sockets of type SOCK_STREAM
+
+ :param ~bytes bytes: some bytes to send"""
+ ...
+ def recv_into(self, buffer: WriteableBuffer, bufsize: int) -> int:
+ """Reads some bytes from the connected remote address, writing
+ into the provided buffer. If bufsize <= len(buffer) is given,
+ a maximum of bufsize bytes will be read into the buffer. If no
+ valid value is given for bufsize, the default is the length of
+ the given buffer.
+
+ Suits sockets of type SOCK_STREAM
+ Returns an int of number of bytes read.
+
+ :param bytearray buffer: buffer to receive into
+ :param int bufsize: optionally, a maximum number of bytes to read."""
+ ...
+ def sendto(self, bytes: ReadableBuffer, address: Tuple[str, int]) -> int:
+ """Send some bytes to a specific address.
+ Suits sockets of type SOCK_DGRAM
+
+ :param ~bytes bytes: some bytes to send
+ :param ~tuple address: tuple of (remote_address, remote_port)"""
+ ...
+ def recvfrom_into(self, buffer: WriteableBuffer) -> Tuple[int, Tuple[str, int]]:
+ """Reads some bytes from a remote address.
+
+ Returns a tuple containing
+ * the number of bytes received into the given buffer
+ * a remote_address, which is a tuple of ip address and port number
+
+ :param object buffer: buffer to read into"""
+ ...
+ def settimeout(self, value: int) -> None:
+ """Set the timeout value for this socket.
+
+ :param ~int value: timeout in seconds. 0 means non-blocking. None means block indefinitely."""
+ ...
+ def __hash__(self) -> int:
+ """Returns a hash for the Socket."""
+ ...
+
+class SocketPool:
+ """A pool of socket resources available for the given radio. Only one
+ SocketPool can be created for each radio.
+
+ SocketPool should be used in place of CPython's socket which provides
+ a pool of sockets provided by the underlying OS."""
+
+ AF_INET: int
+ AF_INET6: int
+ SOCK_STREAM: int
+ SOCK_DGRAM: int
+ SOCK_RAW: int
+ IPPROTO_TCP: int
+ def socket(
+ self, family: int = AF_INET, type: int = SOCK_STREAM, proto: int = IPPROTO_TCP
+ ) -> socketpool.Socket:
+ """Create a new socket
+
+ :param ~int family: AF_INET or AF_INET6
+ :param ~int type: SOCK_STREAM, SOCK_DGRAM or SOCK_RAW
+ :param ~int proto: IPPROTO_TCP, IPPROTO_UDP or IPPROTO_RAW (ignored)"""
+ ...
+
+def getaddrinfo(
+ host: str, port: int, family: int = 0, type: int = 0, proto: int = 0, flags: int = 0
+) -> Tuple[int, int, int, str, Tuple[str, int]]:
+ """Gets the address information for a hostname and port
+
+ Returns the appropriate family, socket type, socket protocol and
+ address information to call socket.socket() and socket.connect() with,
+ as a tuple."""
+ ...
diff --git a/stubs/ssl/__init__.pyi b/stubs/ssl/__init__.pyi
new file mode 100644
index 0000000..7a4ee8c
--- /dev/null
+++ b/stubs/ssl/__init__.pyi
@@ -0,0 +1,29 @@
+"""
+The `ssl` module provides SSL contexts to wrap sockets in.
+"""
+
+from __future__ import annotations
+
+import ssl
+from typing import Optional
+
+import socketpool
+
+def create_default_context() -> ssl.SSLContext:
+ """Return the default SSLContext."""
+ ...
+
+class SSLContext:
+ """Settings related to SSL that can be applied to a socket by wrapping it.
+ This is useful to provide SSL certificates to specific connections
+ rather than all of them."""
+
+def wrap_socket(
+ sock: socketpool.Socket,
+ *,
+ server_side: bool = False,
+ server_hostname: Optional[str] = None
+) -> socketpool.Socket:
+ """Wraps the socket into a socket-compatible class that handles SSL negotiation.
+ The socket must be of type SOCK_STREAM."""
+ ...
diff --git a/stubs/storage/__init__.pyi b/stubs/storage/__init__.pyi
new file mode 100644
index 0000000..aa3acad
--- /dev/null
+++ b/stubs/storage/__init__.pyi
@@ -0,0 +1,103 @@
+"""Storage management
+
+The `storage` provides storage management functionality such as mounting and
+unmounting which is typically handled by the operating system hosting Python.
+CircuitPython does not have an OS, so this module provides this functionality
+directly."""
+
+from __future__ import annotations
+
+from typing import AnyStr, Iterator, Tuple, Union
+
+def mount(filesystem: VfsFat, mount_path: str, *, readonly: bool = False) -> None:
+ """Mounts the given filesystem object at the given path.
+
+ This is the CircuitPython analog to the UNIX ``mount`` command.
+
+ :param bool readonly: True when the filesystem should be readonly to CircuitPython."""
+ ...
+
+def umount(mount: Union[str, VfsFat]) -> None:
+ """Unmounts the given filesystem object or if *mount* is a path, then unmount
+ the filesystem mounted at that location.
+
+ This is the CircuitPython analog to the UNIX ``umount`` command."""
+ ...
+
+def remount(
+ mount_path: str,
+ readonly: bool = False,
+ *,
+ disable_concurrent_write_protection: bool = False
+) -> None:
+ """Remounts the given path with new parameters.
+
+ :param bool readonly: True when the filesystem should be readonly to CircuitPython.
+ :param bool disable_concurrent_write_protection: When True, the check that makes sure the
+ underlying filesystem data is written by one computer is disabled. Disabling the protection
+ allows CircuitPython and a host to write to the same filesystem with the risk that the
+ filesystem will be corrupted."""
+ ...
+
+def getmount(mount_path: str) -> VfsFat:
+ """Retrieves the mount object associated with the mount path"""
+ ...
+
+def erase_filesystem() -> None:
+ """Erase and re-create the ``CIRCUITPY`` filesystem.
+
+ On boards that present USB-visible ``CIRCUITPY`` drive (e.g., SAMD21 and SAMD51),
+ then call `microcontroller.reset()` to restart CircuitPython and have the
+ host computer remount CIRCUITPY.
+
+ This function can be called from the REPL when ``CIRCUITPY``
+ has become corrupted.
+
+ .. warning:: All the data on ``CIRCUITPY`` will be lost, and
+ CircuitPython will restart on certain boards."""
+ ...
+
+class VfsFat:
+ def __init__(self, block_device: str) -> None:
+ """Create a new VfsFat filesystem around the given block device.
+
+ :param block_device: Block device the the filesystem lives on"""
+ label: str
+ """The filesystem label, up to 11 case-insensitive bytes. Note that
+ this property can only be set when the device is writable by the
+ microcontroller."""
+ ...
+ def mkfs(self) -> None:
+ """Format the block device, deleting any data that may have been there"""
+ ...
+ def open(self, path: str, mode: str) -> None:
+ """Like builtin ``open()``"""
+ ...
+ def ilistdir(
+ self, path: str
+ ) -> Iterator[Union[Tuple[AnyStr, int, int, int], Tuple[AnyStr, int, int]]]:
+ """Return an iterator whose values describe files and folders within
+ ``path``"""
+ ...
+ def mkdir(self, path: str) -> None:
+ """Like `os.mkdir`"""
+ ...
+ def rmdir(self, path: str) -> None:
+ """Like `os.rmdir`"""
+ ...
+ def stat(
+ self, path: str
+ ) -> Tuple[int, int, int, int, int, int, int, int, int, int]:
+ """Like `os.stat`"""
+ ...
+ def statvfs(
+ self, path: int
+ ) -> Tuple[int, int, int, int, int, int, int, int, int, int]:
+ """Like `os.statvfs`"""
+ ...
+ def mount(self, readonly: bool, mkfs: VfsFat) -> None:
+ """Don't call this directly, call `storage.mount`."""
+ ...
+ def umount(self) -> None:
+ """Don't call this directly, call `storage.umount`."""
+ ...
diff --git a/stubs/struct/__init__.pyi b/stubs/struct/__init__.pyi
new file mode 100644
index 0000000..3c73365
--- /dev/null
+++ b/stubs/struct/__init__.pyi
@@ -0,0 +1,43 @@
+"""Manipulation of c-style data
+
+This module implements a subset of the corresponding CPython module,
+as described below. For more information, refer to the original CPython
+documentation: struct.
+
+Supported size/byte order prefixes: *@*, *<*, *>*, *!*.
+
+Supported format codes: *b*, *B*, *x*, *h*, *H*, *i*, *I*, *l*, *L*, *q*, *Q*,
+*s*, *P*, *f*, *d* (the latter 2 depending on the floating-point support)."""
+
+from __future__ import annotations
+
+from typing import Any, Tuple
+
+from _typing import ReadableBuffer, WriteableBuffer
+
+def calcsize(fmt: str) -> int:
+ """Return the number of bytes needed to store the given fmt."""
+ ...
+
+def pack(fmt: str, *values: Any) -> bytes:
+ """Pack the values according to the format string fmt.
+ The return value is a bytes object encoding the values."""
+ ...
+
+def pack_into(fmt: str, buffer: WriteableBuffer, offset: int, *values: Any) -> None:
+ """Pack the values according to the format string fmt into a buffer
+ starting at offset. offset may be negative to count from the end of buffer."""
+ ...
+
+def unpack(fmt: str, data: ReadableBuffer) -> Tuple[Any, ...]:
+ """Unpack from the data according to the format string fmt. The return value
+ is a tuple of the unpacked values. The buffer size must match the size
+ required by the format."""
+ ...
+
+def unpack_from(fmt: str, data: ReadableBuffer, offset: int = 0) -> Tuple[Any, ...]:
+ """Unpack from the data starting at offset according to the format string fmt.
+ offset may be negative to count from the end of buffer. The return value is
+ a tuple of the unpacked values. The buffer size must be at least as big
+ as the size required by the form."""
+ ...
diff --git a/stubs/supervisor/__init__.pyi b/stubs/supervisor/__init__.pyi
new file mode 100644
index 0000000..52babac
--- /dev/null
+++ b/stubs/supervisor/__init__.pyi
@@ -0,0 +1,70 @@
+"""Supervisor settings"""
+
+from __future__ import annotations
+
+runtime: Runtime
+"""Runtime information, such as ``runtime.serial_connected``
+(USB serial connection status).
+This object is the sole instance of `supervisor.Runtime`."""
+
+def enable_autoreload() -> None:
+ """Enable autoreload based on USB file write activity."""
+ ...
+
+def disable_autoreload() -> None:
+ """Disable autoreload based on USB file write activity until
+ `enable_autoreload` is called."""
+ ...
+
+def set_rgb_status_brightness(brightness: int) -> None:
+ """Set brightness of status neopixel from 0-255
+ `set_rgb_status_brightness` is called."""
+ ...
+
+def reload() -> None:
+ """Reload the main Python code and run it (equivalent to hitting Ctrl-D at the REPL)."""
+ ...
+
+def set_next_stack_limit(size: int) -> None:
+ """Set the size of the stack for the next vm run. If its too large, the default will be used."""
+ ...
+
+class RunReason:
+ """The reason that CircuitPython started running."""
+
+ STARTUP: object
+ """CircuitPython started the microcontroller started up. See `microcontroller.Processor.reset_reason`
+ for more detail on why the microcontroller was started."""
+
+ AUTO_RELOAD: object
+ """CircuitPython restarted due to an external write to the filesystem."""
+
+ SUPERVISOR_RELOAD: object
+ """CircuitPython restarted due to a call to `supervisor.reload()`."""
+
+ REPL_RELOAD: object
+ """CircuitPython started due to the user typing CTRL-D in the REPL."""
+
+class Runtime:
+ """Current status of runtime objects.
+
+ Usage::
+
+ import supervisor
+ if supervisor.runtime.serial_connected:
+ print("Hello World!")"""
+
+ def __init__(self) -> None:
+ """You cannot create an instance of `supervisor.Runtime`.
+ Use `supervisor.runtime` to access the sole instance available."""
+ ...
+ serial_connected: bool
+ """Returns the USB serial communication status (read-only)."""
+
+ serial_bytes_available: int
+ """Returns the whether any bytes are available to read
+ on the USB serial input. Allows for polling to see whether
+ to call the built-in input() or wait. (read-only)"""
+
+ run_reason: RunReason
+ """Returns why CircuitPython started running this particular time."""
diff --git a/stubs/terminalio/__init__.pyi b/stubs/terminalio/__init__.pyi
new file mode 100644
index 0000000..020ab86
--- /dev/null
+++ b/stubs/terminalio/__init__.pyi
@@ -0,0 +1,29 @@
+"""Displays text in a TileGrid
+
+The `terminalio` module contains classes to display a character stream on a display. The built
+in font is available as ``terminalio.FONT``."""
+
+from __future__ import annotations
+
+from typing import Optional
+
+import displayio
+import fontio
+from _typing import ReadableBuffer
+
+FONT: fontio.BuiltinFont
+"""The built in font"""
+
+class Terminal:
+ """Display a character stream with a TileGrid"""
+
+ def __init__(self, tilegrid: displayio.TileGrid, font: fontio.BuiltinFont) -> None:
+ """Terminal manages tile indices and cursor position based on VT100 commands. The font should be
+ a `fontio.BuiltinFont` and the TileGrid's bitmap should match the font's bitmap."""
+ ...
+ def write(self, buf: ReadableBuffer) -> Optional[int]:
+ """Write the buffer of bytes to the bus.
+
+ :return: the number of bytes written
+ :rtype: int or None"""
+ ...
diff --git a/stubs/time/__init__.pyi b/stubs/time/__init__.pyi
new file mode 100644
index 0000000..4818de5
--- /dev/null
+++ b/stubs/time/__init__.pyi
@@ -0,0 +1,76 @@
+"""time and timing related functions
+
+The `time` module is a strict subset of the CPython `cpython:time` module. So, code
+written in MicroPython will work in CPython but not necessarily the other
+way around."""
+
+from __future__ import annotations
+
+from typing import Tuple
+
+def monotonic() -> float:
+ """Returns an always increasing value of time with an unknown reference
+ point. Only use it to compare against other values from `monotonic`.
+
+ :return: the current monotonic time
+ :rtype: float"""
+ ...
+
+def sleep(seconds: float) -> None:
+ """Sleep for a given number of seconds.
+
+ :param float seconds: the time to sleep in fractional seconds"""
+ ...
+
+class struct_time:
+ def __init__(
+ self, time_tuple: Tuple[int, int, int, int, int, int, int, int, int]
+ ) -> None:
+ """Structure used to capture a date and time. Note that it takes a tuple!
+
+ :param tuple time_tuple: Tuple of time info: ``(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)``
+
+ * ``tm_year``: the year, 2017 for example
+ * ``tm_month``: the month, range [1, 12]
+ * ``tm_mday``: the day of the month, range [1, 31]
+ * ``tm_hour``: the hour, range [0, 23]
+ * ``tm_min``: the minute, range [0, 59]
+ * ``tm_sec``: the second, range [0, 61]
+ * ``tm_wday``: the day of the week, range [0, 6], Monday is 0
+ * ``tm_yday``: the day of the year, range [1, 366], -1 indicates not known
+ * ``tm_isdst``: 1 when in daylight savings, 0 when not, -1 if unknown."""
+ ...
+
+def time() -> int:
+ """Return the current time in seconds since since Jan 1, 1970.
+
+ :return: the current time
+ :rtype: int"""
+ ...
+
+def monotonic_ns() -> int:
+ """Return the time of the monotonic clock, cannot go backward, in nanoseconds.
+
+ :return: the current time
+ :rtype: int"""
+ ...
+
+def localtime(secs: int) -> struct_time:
+ """Convert a time expressed in seconds since Jan 1, 1970 to a struct_time in
+ local time. If secs is not provided or None, the current time as returned
+ by time() is used.
+ The earliest date for which it can generate a time is Jan 1, 2000.
+
+ :return: the current time
+ :rtype: time.struct_time"""
+ ...
+
+def mktime(t: struct_time) -> int:
+ """This is the inverse function of localtime(). Its argument is the
+ struct_time or full 9-tuple (since the dst flag is needed; use -1 as the
+ dst flag if it is unknown) which expresses the time in local time, not UTC.
+ The earliest date for which it can generate a time is Jan 1, 2000.
+
+ :return: seconds
+ :rtype: int"""
+ ...
diff --git a/stubs/touchio/__init__.pyi b/stubs/touchio/__init__.pyi
new file mode 100644
index 0000000..92beed3
--- /dev/null
+++ b/stubs/touchio/__init__.pyi
@@ -0,0 +1,70 @@
+"""Touch related IO
+
+The `touchio` module contains classes to provide access to touch IO typically
+accelerated by hardware on the onboard microcontroller.
+
+All classes change hardware state and should be deinitialized when they
+are no longer needed if the program continues after use. To do so, either
+call :py:meth:`!deinit` or use a context manager. See
+:ref:`lifetime-and-contextmanagers` for more info.
+
+For example::
+
+ import touchio
+ from board import *
+
+ touch_pin = touchio.TouchIn(D6)
+ print(touch_pin.value)
+
+This example will initialize the the device, and print the
+:py:data:`~touchio.TouchIn.value`."""
+
+from __future__ import annotations
+
+from typing import Optional
+
+import microcontroller
+
+class TouchIn:
+ """Read the state of a capacitive touch sensor
+
+ Usage::
+
+ import touchio
+ from board import *
+
+ touch = touchio.TouchIn(A1)
+ while True:
+ if touch.value:
+ print("touched!")"""
+
+ def __init__(self, pin: microcontroller.Pin) -> None:
+ """Use the TouchIn on the given pin.
+
+ :param ~microcontroller.Pin pin: the pin to read from"""
+ ...
+ def deinit(self) -> None:
+ """Deinitialises the TouchIn and releases any hardware resources for reuse."""
+ ...
+ def __enter__(self) -> TouchIn:
+ """No-op used by Context Managers."""
+ ...
+ def __exit__(self) -> None:
+ """Automatically deinitializes the hardware when exiting a context. See
+ :ref:`lifetime-and-contextmanagers` for more info."""
+ ...
+ value: bool
+ """Whether the touch pad is being touched or not. (read-only)
+
+ True when `raw_value` > `threshold`."""
+
+ raw_value: int
+ """The raw touch measurement as an `int`. (read-only)"""
+
+ threshold: Optional[int]
+ """Minimum `raw_value` needed to detect a touch (and for `value` to be `True`).
+
+ When the **TouchIn** object is created, an initial `raw_value` is read from the pin,
+ and then `threshold` is set to be 100 + that value.
+
+ You can adjust `threshold` to make the pin more or less sensitive."""
diff --git a/stubs/uheap/__init__.pyi b/stubs/uheap/__init__.pyi
new file mode 100644
index 0000000..8476997
--- /dev/null
+++ b/stubs/uheap/__init__.pyi
@@ -0,0 +1,8 @@
+"""Heap size analysis"""
+
+from __future__ import annotations
+
+def info(object: object) -> int:
+ """Prints memory debugging info for the given object and returns the
+ estimated size."""
+ ...
diff --git a/stubs/ulab/__init__.pyi b/stubs/ulab/__init__.pyi
new file mode 100644
index 0000000..186f44b
--- /dev/null
+++ b/stubs/ulab/__init__.pyi
@@ -0,0 +1,315 @@
+"""Manipulate numeric data similar to numpy
+
+`ulab` is a numpy-like module for micropython, meant to simplify and
+speed up common mathematical operations on arrays. The primary goal was to
+implement a small subset of numpy that might be useful in the context of a
+microcontroller. This means low-level data processing of linear (array) and
+two-dimensional (matrix) data.
+
+`ulab` is adapted from micropython-ulab, and the original project's
+documentation can be found at
+https://micropython-ulab.readthedocs.io/en/latest/
+
+`ulab` is modeled after numpy, and aims to be a compatible subset where
+possible. Numpy's documentation can be found at
+https://docs.scipy.org/doc/numpy/index.html"""
+
+from __future__ import annotations
+
+from typing import Any, Dict, Iterable, Iterator, List, Optional, Tuple, Union, overload
+
+import ulab
+
+_DType = int
+"""`ulab.int8`, `ulab.uint8`, `ulab.int16`, `ulab.uint16`, `ulab.float` or `ulab.bool`"""
+
+_float = float
+"""Type alias of the bulitin float"""
+
+_bool = bool
+"""Type alias of the bulitin bool"""
+
+_Index = Union[int, slice, ulab.array, Tuple[Union[int, slice], ...]]
+
+class array:
+ """1- and 2- dimensional array"""
+
+ def __init__(
+ self,
+ values: Union[array, Iterable[Union[_float, _bool, Iterable[Any]]]],
+ *,
+ dtype: _DType = ulab.float
+ ) -> None:
+ """:param sequence values: Sequence giving the initial content of the array.
+ :param ~ulab._DType dtype: The type of array values, `ulab.int8`, `ulab.uint8`, `ulab.int16`, `ulab.uint16`, `ulab.float` or `ulab.bool`
+
+ The ``values`` sequence can either be another ~ulab.array, sequence of numbers
+ (in which case a 1-dimensional array is created), or a sequence where each
+ subsequence has the same length (in which case a 2-dimensional array is
+ created).
+
+ Passing a `ulab.array` and a different dtype can be used to convert an array
+ from one dtype to another.
+
+ In many cases, it is more convenient to create an array from a function
+ like `zeros` or `linspace`.
+
+ `ulab.array` implements the buffer protocol, so it can be used in many
+ places an `array.array` can be used."""
+ ...
+ shape: Tuple[int, ...]
+ """The size of the array, a tuple of length 1 or 2"""
+
+ size: int
+ """The number of elements in the array"""
+
+ itemsize: int
+ """The size of a single item in the array"""
+
+ strides: Tuple[int, ...]
+ """Tuple of bytes to step in each dimension, a tuple of length 1 or 2"""
+ def copy(self) -> ulab.array:
+ """Return a copy of the array"""
+ ...
+ def flatten(self, *, order: str = "C") -> ulab.array:
+ """:param order: Whether to flatten by rows ('C') or columns ('F')
+
+ Returns a new `ulab.array` object which is always 1 dimensional.
+ If order is 'C' (the default", then the data is ordered in rows;
+ If it is 'F', then the data is ordered in columns. "C" and "F" refer
+ to the typical storage organization of the C and Fortran languages."""
+ ...
+ def reshape(self, shape: Tuple[int, ...]) -> ulab.array:
+ """Returns an array containing the same data with a new shape."""
+ ...
+ def sort(self, *, axis: Optional[int] = 1) -> None:
+ """:param axis: Whether to sort elements within rows (0), columns (1), or elements (None)"""
+ ...
+ def tobytes(self) -> bytearray:
+ """Return the raw data bytes in the array"""
+ ...
+ def transpose(self) -> ulab.array:
+ """Swap the rows and columns of a 2-dimensional array"""
+ ...
+ def __add__(self, other: Union[array, _float]) -> ulab.array:
+ """Adds corresponding elements of the two arrays, or adds a number to all
+ elements of the array. If both arguments are arrays, their sizes must match."""
+ ...
+ def __radd__(self, other: _float) -> ulab.array: ...
+ def __sub__(self, other: Union[array, _float]) -> ulab.array:
+ """Subtracts corresponding elements of the two arrays, or subtracts a number from all
+ elements of the array. If both arguments are arrays, their sizes must match."""
+ ...
+ def __rsub__(self, other: _float) -> ulab.array: ...
+ def __mul__(self, other: Union[array, _float]) -> ulab.array:
+ """Multiplies corresponding elements of the two arrays, or multiplies
+ all elements of the array by a number. If both arguments are arrays,
+ their sizes must match."""
+ ...
+ def __rmul__(self, other: _float) -> ulab.array: ...
+ def __div__(self, other: Union[array, _float]) -> ulab.array:
+ """Multiplies corresponding elements of the two arrays, or divides
+ all elements of the array by a number. If both arguments are arrays,
+ their sizes must match."""
+ ...
+ def __rdiv__(self, other: _float) -> ulab.array: ...
+ def __pow__(self, other: Union[array, _float]) -> ulab.array:
+ """Computes the power (x**y) of corresponding elements of the the two arrays,
+ or one number and one array. If both arguments are arrays, their sizes
+ must match."""
+ ...
+ def __rpow__(self, other: _float) -> ulab.array: ...
+ def __inv__(self) -> ulab.array: ...
+ def __neg__(self) -> ulab.array: ...
+ def __pos__(self) -> ulab.array: ...
+ def __abs__(self) -> ulab.array: ...
+ def __len__(self) -> int: ...
+ def __lt__(self, other: Union[array, _float]) -> ulab.array: ...
+ def __le__(self, other: Union[array, _float]) -> ulab.array: ...
+ def __gt__(self, other: Union[array, _float]) -> ulab.array: ...
+ def __ge__(self, other: Union[array, _float]) -> ulab.array: ...
+ def __iter__(self) -> Union[Iterator[array], Iterator[_float]]: ...
+ def __getitem__(self, index: _Index) -> Union[array, _float]:
+ """Retrieve an element of the array."""
+ ...
+ def __setitem__(self, index: _Index, value: Union[array, _float]) -> None:
+ """Set an element of the array."""
+ ...
+
+_ArrayLike = Union[array, List[_float], Tuple[_float], range]
+"""`ulab.array`, ``List[float]``, ``Tuple[float]`` or `range`"""
+
+int8: _DType
+"""Type code for signed integers in the range -128 .. 127 inclusive, like the 'b' typecode of `array.array`"""
+
+int16: _DType
+"""Type code for signed integers in the range -32768 .. 32767 inclusive, like the 'h' typecode of `array.array`"""
+
+float: _DType
+"""Type code for floating point values, like the 'f' typecode of `array.array`"""
+
+uint8: _DType
+"""Type code for unsigned integers in the range 0 .. 255 inclusive, like the 'H' typecode of `array.array`"""
+
+uint16: _DType
+"""Type code for unsigned integers in the range 0 .. 65535 inclusive, like the 'h' typecode of `array.array`"""
+
+bool: _DType
+"""Type code for boolean values"""
+
+def get_printoptions() -> Dict[str, int]:
+ """Get printing options"""
+ ...
+
+def set_printoptions(
+ threshold: Optional[int] = None, edgeitems: Optional[int] = None
+) -> None:
+ """Set printing options"""
+ ...
+
+def ndinfo(array: ulab.array) -> None: ...
+@overload
+def arange(
+ stop: _float, step: _float = 1, *, dtype: _DType = ulab.float
+) -> ulab.array: ...
+@overload
+def arange(
+ start: _float, stop: _float, step: _float = 1, *, dtype: _DType = ulab.float
+) -> ulab.array:
+ """
+ .. param: start
+ First value in the array, optional, defaults to 0
+ .. param: stop
+ Final value in the array
+ .. param: step
+ Difference between consecutive elements, optional, defaults to 1.0
+ .. param: dtype
+ Type of values in the array
+
+ Return a new 1-D array with elements ranging from ``start`` to ``stop``, with step size ``step``."""
+ ...
+
+def concatenate(arrays: Tuple[ulab.array], *, axis: int = 0) -> ulab.array:
+ """
+ .. param: arrays
+ tuple of ndarrays
+ .. param: axis
+ axis along which the arrays will be joined
+
+ Join a sequence of arrays along an existing axis."""
+ ...
+
+def diagonal(a: ulab.array, *, offset: int = 0) -> ulab.array:
+ """
+ .. param: a
+ an ndarray
+ .. param: offset
+ Offset of the diagonal from the main diagonal. Can be positive or negative.
+
+ Return specified diagonals."""
+ ...
+
+def eye(
+ size: int, *, M: Optional[int] = None, k: int = 0, dtype: _DType = ulab.float
+) -> ulab.array:
+ """Return a new square array of size, with the diagonal elements set to 1
+ and the other elements set to 0."""
+ ...
+
+def full(
+ shape: Union[int, Tuple[int, ...]],
+ fill_value: Union[_float, _bool],
+ *,
+ dtype: _DType = ulab.float
+) -> ulab.array:
+ """
+ .. param: shape
+ Shape of the array, either an integer (for a 1-D array) or a tuple of integers (for tensors of higher rank)
+ .. param: fill_value
+ scalar, the value with which the array is filled
+ .. param: dtype
+ Type of values in the array
+
+ Return a new array of the given shape with all elements set to 0."""
+ ...
+
+def linspace(
+ start: _float,
+ stop: _float,
+ *,
+ dtype: _DType = ulab.float,
+ num: int = 50,
+ endpoint: _bool = True,
+ retstep: _bool = False
+) -> ulab.array:
+ """
+ .. param: start
+ First value in the array
+ .. param: stop
+ Final value in the array
+ .. param int: num
+ Count of values in the array.
+ .. param: dtype
+ Type of values in the array
+ .. param bool: endpoint
+ Whether the ``stop`` value is included. Note that even when
+ endpoint=True, the exact ``stop`` value may not be included due to the
+ inaccuracy of floating point arithmetic.
+ If True, return (`samples`, `step`), where `step` is the spacing between samples.
+
+ Return a new 1-D array with ``num`` elements ranging from ``start`` to ``stop`` linearly."""
+ ...
+
+def logspace(
+ start: _float,
+ stop: _float,
+ *,
+ dtype: _DType = ulab.float,
+ num: int = 50,
+ endpoint: _bool = True,
+ base: _float = 10.0
+) -> ulab.array:
+ """
+ .. param: start
+ First value in the array
+ .. param: stop
+ Final value in the array
+ .. param int: num
+ Count of values in the array. Defaults to 50.
+ .. param: base
+ The base of the log space. The step size between the elements in
+ ``ln(samples) / ln(base)`` (or ``log_base(samples)``) is uniform. Defaults to 10.0.
+ .. param: dtype
+ Type of values in the array
+ .. param bool: endpoint
+ Whether the ``stop`` value is included. Note that even when
+ endpoint=True, the exact ``stop`` value may not be included due to the
+ inaccuracy of floating point arithmetic. Defaults to True.
+
+ Return a new 1-D array with ``num`` evenly spaced elements on a log scale.
+ The sequence starts at ``base ** start``, and ends with ``base ** stop``."""
+ ...
+
+def ones(
+ shape: Union[int, Tuple[int, ...]], *, dtype: _DType = ulab.float
+) -> ulab.array:
+ """
+ .. param: shape
+ Shape of the array, either an integer (for a 1-D array) or a tuple of 2 integers (for a 2-D array)
+ .. param: dtype
+ Type of values in the array
+
+ Return a new array of the given shape with all elements set to 1."""
+ ...
+
+def zeros(
+ shape: Union[int, Tuple[int, ...]], *, dtype: _DType = ulab.float
+) -> ulab.array:
+ """
+ .. param: shape
+ Shape of the array, either an integer (for a 1-D array) or a tuple of 2 integers (for a 2-D array)
+ .. param: dtype
+ Type of values in the array
+
+ Return a new array of the given shape with all elements set to 0."""
+ ...
diff --git a/stubs/ulab/approx/__init__.pyi b/stubs/ulab/approx/__init__.pyi
new file mode 100644
index 0000000..c2e221b
--- /dev/null
+++ b/stubs/ulab/approx/__init__.pyi
@@ -0,0 +1,95 @@
+"""Numerical approximation methods"""
+
+from __future__ import annotations
+
+from typing import Callable, Optional
+
+import ulab
+
+def bisect(
+ fun: Callable[[float], float],
+ a: float,
+ b: float,
+ *,
+ xtol: float = 2.4e-7,
+ maxiter: int = 100
+) -> float:
+ """
+ :param callable f: The function to bisect
+ :param float a: The left side of the interval
+ :param float b: The right side of the interval
+ :param float xtol: The tolerance value
+ :param float maxiter: The maximum number of iterations to perform
+
+ Find a solution (zero) of the function ``f(x)`` on the interval
+ (``a``..``b``) using the bisection method. The result is accurate to within
+ ``xtol`` unless more than ``maxiter`` steps are required."""
+ ...
+
+def fmin(
+ fun: Callable[[float], float],
+ x0: float,
+ *,
+ xatol: float = 2.4e-7,
+ fatol: float = 2.4e-7,
+ maxiter: int = 200
+) -> float:
+ """
+ :param callable f: The function to bisect
+ :param float x0: The initial x value
+ :param float xatol: The absolute tolerance value
+ :param float fatol: The relative tolerance value
+
+ Find a minimum of the function ``f(x)`` using the downhill simplex method.
+ The located ``x`` is within ``fxtol`` of the actual minimum, and ``f(x)``
+ is within ``fatol`` of the actual minimum unless more than ``maxiter``
+ steps are requried."""
+ ...
+
+def interp(
+ x: ulab.array,
+ xp: ulab.array,
+ fp: ulab.array,
+ *,
+ left: Optional[float] = None,
+ right: Optional[float] = None
+) -> ulab.array:
+ """
+ :param ulab.array x: The x-coordinates at which to evaluate the interpolated values.
+ :param ulab.array xp: The x-coordinates of the data points, must be increasing
+ :param ulab.array fp: The y-coordinates of the data points, same length as xp
+ :param left: Value to return for ``x < xp[0]``, default is ``fp[0]``.
+ :param right: Value to return for ``x > xp[-1]``, default is ``fp[-1]``.
+
+ Returns the one-dimensional piecewise linear interpolant to a function with given discrete data points (xp, fp), evaluated at x."""
+ ...
+
+def newton(
+ fun: Callable[[float], float],
+ x0: float,
+ *,
+ xtol: float = 2.4e-7,
+ rtol: float = 0.0,
+ maxiter: int = 50
+) -> float:
+ """
+ :param callable f: The function to bisect
+ :param float x0: The initial x value
+ :param float xtol: The absolute tolerance value
+ :param float rtol: The relative tolerance value
+ :param float maxiter: The maximum number of iterations to perform
+
+ Find a solution (zero) of the function ``f(x)`` using Newton's Method.
+ The result is accurate to within ``xtol * rtol * |f(x)|`` unless more than
+ ``maxiter`` steps are requried."""
+ ...
+
+def trapz(y: ulab.array, x: Optional[ulab.array] = None, dx: float = 1.0) -> float:
+ """
+ :param 1D ulab.array y: the values of the dependent variable
+ :param 1D ulab.array x: optional, the coordinates of the independent variable. Defaults to uniformly spaced values.
+ :param float dx: the spacing between sample points, if x=None
+
+ Returns the integral of y(x) using the trapezoidal rule.
+ """
+ ...
diff --git a/stubs/ulab/compare/__init__.pyi b/stubs/ulab/compare/__init__.pyi
new file mode 100644
index 0000000..a1dd080
--- /dev/null
+++ b/stubs/ulab/compare/__init__.pyi
@@ -0,0 +1,48 @@
+"""Comparison functions"""
+
+from __future__ import annotations
+
+from typing import List, Union
+
+import ulab
+
+def clip(
+ x1: Union[ulab.array, float],
+ x2: Union[ulab.array, float],
+ x3: Union[ulab.array, float],
+) -> ulab.array:
+ """
+ Constrain the values from ``x1`` to be between ``x2`` and ``x3``.
+ ``x2`` is assumed to be less than or equal to ``x3``.
+
+ Arguments may be ulab arrays or numbers. All array arguments
+ must be the same size. If the inputs are all scalars, a 1-element
+ array is returned.
+
+ Shorthand for ``ulab.maximum(x2, ulab.minimum(x1, x3))``"""
+ ...
+
+def equal(x1: Union[ulab.array, float], x2: Union[ulab.array, float]) -> List[bool]:
+ """Return an array of bool which is true where x1[i] == x2[i] and false elsewhere"""
+ ...
+
+def not_equal(x1: Union[ulab.array, float], x2: Union[ulab.array, float]) -> List[bool]:
+ """Return an array of bool which is false where x1[i] == x2[i] and true elsewhere"""
+ ...
+
+def maximum(x1: Union[ulab.array, float], x2: Union[ulab.array, float]) -> ulab.array:
+ """
+ Compute the element by element maximum of the arguments.
+
+ Arguments may be ulab arrays or numbers. All array arguments
+ must be the same size. If the inputs are both scalars, a number is
+ returned"""
+ ...
+
+def minimum(x1: Union[ulab.array, float], x2: Union[ulab.array, float]) -> ulab.array:
+ """Compute the element by element minimum of the arguments.
+
+ Arguments may be ulab arrays or numbers. All array arguments
+ must be the same size. If the inputs are both scalars, a number is
+ returned"""
+ ...
diff --git a/stubs/ulab/fft/__init__.pyi b/stubs/ulab/fft/__init__.pyi
new file mode 100644
index 0000000..103a9ab
--- /dev/null
+++ b/stubs/ulab/fft/__init__.pyi
@@ -0,0 +1,38 @@
+"""Frequency-domain functions"""
+
+from __future__ import annotations
+
+from typing import Optional, Tuple
+
+import ulab
+
+def fft(r: ulab.array, c: Optional[ulab.array] = None) -> Tuple[ulab.array, ulab.array]:
+ """
+ :param ulab.array r: A 1-dimension array of values whose size is a power of 2
+ :param ulab.array c: An optional 1-dimension array of values whose size is a power of 2, giving the complex part of the value
+ :return tuple (r, c): The real and complex parts of the FFT
+
+ Perform a Fast Fourier Transform from the time domain into the frequency domain
+
+ See also ~ulab.extras.spectrum, which computes the magnitude of the fft,
+ rather than separately returning its real and imaginary parts."""
+ ...
+
+def ifft(
+ r: ulab.array, c: Optional[ulab.array] = None
+) -> Tuple[ulab.array, ulab.array]:
+ """
+ :param ulab.array r: A 1-dimension array of values whose size is a power of 2
+ :param ulab.array c: An optional 1-dimension array of values whose size is a power of 2, giving the complex part of the value
+ :return tuple (r, c): The real and complex parts of the inverse FFT
+
+ Perform an Inverse Fast Fourier Transform from the frequeny domain into the time domain"""
+ ...
+
+def spectrogram(r: ulab.array) -> ulab.array:
+ """
+ :param ulab.array r: A 1-dimension array of values whose size is a power of 2
+
+ Computes the spectrum of the input signal. This is the absolute value of the (complex-valued) fft of the signal.
+ This function is similar to scipy's ``scipy.signal.spectrogram``."""
+ ...
diff --git a/stubs/ulab/filter/__init__.pyi b/stubs/ulab/filter/__init__.pyi
new file mode 100644
index 0000000..6330e7a
--- /dev/null
+++ b/stubs/ulab/filter/__init__.pyi
@@ -0,0 +1,47 @@
+"""Filtering functions"""
+
+from __future__ import annotations
+
+from typing import Tuple, overload
+
+import ulab
+from ulab import _ArrayLike
+
+def convolve(a: ulab.array, v: ulab.array) -> ulab.array:
+ """
+ :param ulab.array a:
+ :param ulab.array v:
+
+ Returns the discrete, linear convolution of two one-dimensional sequences.
+ The result is always an array of float. Only the ``full`` mode is supported,
+ and the ``mode`` named parameter of numpy is not accepted. Note that all other
+ modes can be had by slicing a ``full`` result.
+
+ Convolution filters can implement high pass, low pass, band pass, etc.,
+ filtering operations. Convolution filters are typically constructed ahead
+ of time. This can be done using desktop python with scipy, or on web pages
+ such as https://fiiir.com/
+
+ Convolution is most time-efficient when both inputs are of float type."""
+ ...
+
+@overload
+def sosfilt(sos: _ArrayLike, x: _ArrayLike) -> ulab.array: ...
+@overload
+def sosfilt(
+ sos: _ArrayLike, x: _ArrayLike, *, zi: ulab.array
+) -> Tuple[ulab.array, ulab.array]:
+ """
+ :param ulab.array sos: Array of second-order filter coefficients, must have shape (n_sections, 6). Each row corresponds to a second-order section, with the first three columns providing the numerator coefficients and the last three providing the denominator coefficients.
+ :param ulab.array x: The data to be filtered
+ :param ulab.array zi: Optional initial conditions for the filter
+ :return: If ``zi`` is not specified, the filter result alone is returned. If ``zi`` is specified, the return value is a 2-tuple of the filter result and the final filter conditions.
+
+ Filter data along one dimension using cascaded second-order sections.
+
+ Filter a data sequence, x, using a digital IIR filter defined by sos.
+
+ The filter function is implemented as a series of second-order filters with direct-form II transposed structure. It is designed to minimize numerical precision errors for high-order filters.
+
+ Filter coefficients can be generated by using scipy's filter generators such as ``signal.ellip(..., output='sos')``."""
+ ...
diff --git a/stubs/ulab/linalg/__init__.pyi b/stubs/ulab/linalg/__init__.pyi
new file mode 100644
index 0000000..0bec54c
--- /dev/null
+++ b/stubs/ulab/linalg/__init__.pyi
@@ -0,0 +1,67 @@
+"""Linear algebra functions"""
+
+from __future__ import annotations
+
+from typing import Optional, Tuple, Union
+
+import ulab
+
+def cholesky(A: ulab.array) -> ulab.array:
+ """
+ :param ~ulab.array A: a positive definite, symmetric square matrix
+ :return ~ulab.array L: a square root matrix in the lower triangular form
+ :raises ValueError: If the input does not fulfill the necessary conditions
+
+ The returned matrix satisfies the equation m=LL*"""
+ ...
+
+def det(m: ulab.array) -> float:
+ """
+ :param: m, a square matrix
+ :return float: The determinant of the matrix
+
+ Computes the eigenvalues and eigenvectors of a square matrix"""
+ ...
+
+def dot(m1: ulab.array, m2: ulab.array) -> Union[ulab.array, float]:
+ """
+ :param ~ulab.array m1: a matrix, or a vector
+ :param ~ulab.array m2: a matrix, or a vector
+
+ Computes the product of two matrices, or two vectors. In the letter case, the inner product is returned."""
+ ...
+
+def eig(m: ulab.array) -> Tuple[ulab.array, ulab.array]:
+ """
+ :param m: a square matrix
+ :return tuple (eigenvectors, eigenvalues):
+
+ Computes the eigenvalues and eigenvectors of a square matrix"""
+ ...
+
+def inv(m: ulab.array) -> ulab.array:
+ """
+ :param ~ulab.array m: a square matrix
+ :return: The inverse of the matrix, if it exists
+ :raises ValueError: if the matrix is not invertible
+
+ Computes the inverse of a square matrix"""
+ ...
+
+def norm(x: ulab.array) -> float:
+ """
+ :param ~ulab.array x: a vector or a matrix
+
+ Computes the 2-norm of a vector or a matrix, i.e., ``sqrt(sum(x*x))``, however, without the RAM overhead."""
+ ...
+
+def size(array: ulab.array, *, axis: Optional[int] = None) -> int:
+ """Return the total number of elements in the array, as an integer."""
+ ...
+
+def trace(m: ulab.array) -> float:
+ """
+ :param m: a square matrix
+
+ Compute the trace of the matrix, the sum of its diagonal elements."""
+ ...
diff --git a/stubs/ulab/numerical/__init__.pyi b/stubs/ulab/numerical/__init__.pyi
new file mode 100644
index 0000000..3218fb0
--- /dev/null
+++ b/stubs/ulab/numerical/__init__.pyi
@@ -0,0 +1,70 @@
+"""Numerical and Statistical functions
+
+Most of these functions take an "axis" argument, which indicates whether to
+operate over the flattened array (None), or a particular axis (integer)."""
+
+from __future__ import annotations
+
+from typing import Optional, Union
+
+import ulab
+from ulab import _ArrayLike
+
+def argmax(array: _ArrayLike, *, axis: Optional[int] = None) -> int:
+ """Return the index of the maximum element of the 1D array"""
+ ...
+
+def argmin(array: _ArrayLike, *, axis: Optional[int] = None) -> int:
+ """Return the index of the minimum element of the 1D array"""
+ ...
+
+def argsort(array: ulab.array, *, axis: int = -1) -> ulab.array:
+ """Returns an array which gives indices into the input array from least to greatest."""
+ ...
+
+def cross(a: ulab.array, b: ulab.array) -> ulab.array:
+ """Return the cross product of two vectors of length 3"""
+ ...
+
+def diff(array: ulab.array, *, n: int = 1, axis: int = -1) -> ulab.array:
+ """Return the numerical derivative of successive elements of the array, as
+ an array. axis=None is not supported."""
+ ...
+
+def flip(array: ulab.array, *, axis: Optional[int] = None) -> ulab.array:
+ """Returns a new array that reverses the order of the elements along the
+ given axis, or along all axes if axis is None."""
+ ...
+
+def max(array: _ArrayLike, *, axis: Optional[int] = None) -> float:
+ """Return the maximum element of the 1D array"""
+ ...
+
+def mean(array: _ArrayLike, *, axis: Optional[int] = None) -> float:
+ """Return the mean element of the 1D array, as a number if axis is None, otherwise as an array."""
+ ...
+
+def min(array: _ArrayLike, *, axis: Optional[int] = None) -> float:
+ """Return the minimum element of the 1D array"""
+ ...
+
+def roll(array: ulab.array, distance: int, *, axis: Optional[int] = None) -> None:
+ """Shift the content of a vector by the positions given as the second
+ argument. If the ``axis`` keyword is supplied, the shift is applied to
+ the given axis. The array is modified in place."""
+ ...
+
+def sort(array: ulab.array, *, axis: int = -1) -> ulab.array:
+ """Sort the array along the given axis, or along all axes if axis is None.
+ The array is modified in place."""
+ ...
+
+def std(array: _ArrayLike, *, axis: Optional[int] = None, ddof: int = 0) -> float:
+ """Return the standard deviation of the array, as a number if axis is None, otherwise as an array."""
+ ...
+
+def sum(
+ array: _ArrayLike, *, axis: Optional[int] = None
+) -> Union[float, int, ulab.array]:
+ """Return the sum of the array, as a number if axis is None, otherwise as an array."""
+ ...
diff --git a/stubs/ulab/poly/__init__.pyi b/stubs/ulab/poly/__init__.pyi
new file mode 100644
index 0000000..b4922b4
--- /dev/null
+++ b/stubs/ulab/poly/__init__.pyi
@@ -0,0 +1,19 @@
+"""Polynomial functions"""
+
+from __future__ import annotations
+
+from typing import overload
+
+import ulab
+from ulab import _ArrayLike
+@overload
+def polyfit(y: _ArrayLike, degree: int) -> ulab.array: ...
+@overload
+def polyfit(x: _ArrayLike, y: _ArrayLike, degree: int) -> ulab.array:
+ """Return a polynomial of given degree that approximates the function
+ f(x)=y. If x is not supplied, it is the range(len(y))."""
+ ...
+
+def polyval(p: _ArrayLike, x: _ArrayLike) -> ulab.array:
+ """Evaluate the polynomial p at the points x. x must be an array."""
+ ...
diff --git a/stubs/ulab/user/__init__.pyi b/stubs/ulab/user/__init__.pyi
new file mode 100644
index 0000000..5db3904
--- /dev/null
+++ b/stubs/ulab/user/__init__.pyi
@@ -0,0 +1,3 @@
+"""This module should hold arbitrary user-defined functions."""
+
+from __future__ import annotations
diff --git a/stubs/ulab/vector/__init__.pyi b/stubs/ulab/vector/__init__.pyi
new file mode 100644
index 0000000..c43f835
--- /dev/null
+++ b/stubs/ulab/vector/__init__.pyi
@@ -0,0 +1,140 @@
+"""Element-by-element functions
+
+These functions can operate on numbers, 1-D iterables, 1-D arrays, or 2-D arrays by
+applying the function to every element in the array. This is typically
+much more efficient than expressing the same operation as a Python loop."""
+
+from __future__ import annotations
+
+from typing import Callable, Optional, Union
+
+import ulab
+from ulab import _ArrayLike, _DType
+
+def acos(a: _ArrayLike) -> ulab.array:
+ """Computes the inverse cosine function"""
+ ...
+
+def acosh(a: _ArrayLike) -> ulab.array:
+ """Computes the inverse hyperbolic cosine function"""
+ ...
+
+def asin(a: _ArrayLike) -> ulab.array:
+ """Computes the inverse sine function"""
+ ...
+
+def asinh(a: _ArrayLike) -> ulab.array:
+ """Computes the inverse hyperbolic sine function"""
+ ...
+
+def around(a: _ArrayLike, *, decimals: int = 0) -> ulab.array:
+ """Returns a new float array in which each element is rounded to
+ ``decimals`` places."""
+ ...
+
+def atan(a: _ArrayLike) -> ulab.array:
+ """Computes the inverse tangent function; the return values are in the
+ range [-pi/2,pi/2]."""
+ ...
+
+def arctan2(ya: _ArrayLike, xa: _ArrayLike) -> ulab.array:
+ """Computes the inverse tangent function of y/x; the return values are in
+ the range [-pi, pi]."""
+ ...
+
+def atanh(a: _ArrayLike) -> ulab.array:
+ """Computes the inverse hyperbolic tangent function"""
+ ...
+
+def ceil(a: _ArrayLike) -> ulab.array:
+ """Rounds numbers up to the next whole number"""
+ ...
+
+def cos(a: _ArrayLike) -> ulab.array:
+ """Computes the cosine function"""
+ ...
+
+def cosh(a: _ArrayLike) -> ulab.array:
+ """Computes the hyperbolic cosine function"""
+ ...
+
+def degrees(a: _ArrayLike) -> ulab.array:
+ """Converts angles from radians to degrees"""
+ ...
+
+def erf(a: _ArrayLike) -> ulab.array:
+ """Computes the error function, which has applications in statistics"""
+ ...
+
+def erfc(a: _ArrayLike) -> ulab.array:
+ """Computes the complementary error function, which has applications in statistics"""
+ ...
+
+def exp(a: _ArrayLike) -> ulab.array:
+ """Computes the exponent function."""
+ ...
+
+def expm1(a: _ArrayLike) -> ulab.array:
+ """Computes $e^x-1$. In certain applications, using this function preserves numeric accuracy better than the `exp` function."""
+ ...
+
+def floor(a: _ArrayLike) -> ulab.array:
+ """Rounds numbers up to the next whole number"""
+ ...
+
+def gamma(a: _ArrayLike) -> ulab.array:
+ """Computes the gamma function"""
+ ...
+
+def lgamma(a: _ArrayLike) -> ulab.array:
+ """Computes the natural log of the gamma function"""
+ ...
+
+def log(a: _ArrayLike) -> ulab.array:
+ """Computes the natural log"""
+ ...
+
+def log10(a: _ArrayLike) -> ulab.array:
+ """Computes the log base 10"""
+ ...
+
+def log2(a: _ArrayLike) -> ulab.array:
+ """Computes the log base 2"""
+ ...
+
+def radians(a: _ArrayLike) -> ulab.array:
+ """Converts angles from degrees to radians"""
+ ...
+
+def sin(a: _ArrayLike) -> ulab.array:
+ """Computes the sine function"""
+ ...
+
+def sinh(a: _ArrayLike) -> ulab.array:
+ """Computes the hyperbolic sine"""
+ ...
+
+def sqrt(a: _ArrayLike) -> ulab.array:
+ """Computes the square root"""
+ ...
+
+def tan(a: _ArrayLike) -> ulab.array:
+ """Computes the tangent"""
+ ...
+
+def tanh(a: _ArrayLike) -> ulab.array:
+ """Computes the hyperbolic tangent"""
+ ...
+
+def vectorize(
+ f: Union[Callable[[int], float], Callable[[float], float]],
+ *,
+ otypes: Optional[_DType] = None
+) -> Callable[[_ArrayLike], ulab.array]:
+ """
+ :param callable f: The function to wrap
+ :param otypes: List of array types that may be returned by the function. None is interpreted to mean the return value is float.
+
+ Wrap a Python function ``f`` so that it can be applied to arrays.
+ The callable must return only values of the types specified by ``otypes``, or the result is undefined."""
+ ...
diff --git a/stubs/usb_hid/__init__.pyi b/stubs/usb_hid/__init__.pyi
new file mode 100644
index 0000000..190d289
--- /dev/null
+++ b/stubs/usb_hid/__init__.pyi
@@ -0,0 +1,41 @@
+"""USB Human Interface Device
+
+The `usb_hid` module allows you to output data as a HID device."""
+
+from __future__ import annotations
+
+from typing import Tuple
+
+from _typing import ReadableBuffer
+
+devices: Tuple[Device, ...]
+"""Tuple of all active HID device interfaces."""
+
+class Device:
+ """HID Device
+
+ Usage::
+
+ import usb_hid
+
+ mouse = usb_hid.devices[0]
+
+ mouse.send_report()"""
+
+ def __init__(self) -> None:
+ """Not currently dynamically supported."""
+ ...
+ def send_report(self, buf: ReadableBuffer) -> None:
+ """Send a HID report."""
+ ...
+ last_received_report: bytes
+ """The HID OUT report as a `bytes`. (read-only). `None` if nothing received."""
+
+ usage_page: int
+ """The usage page of the device as an `int`. Can be thought of a category. (read-only)"""
+
+ usage: int
+ """The functionality of the device as an int. (read-only)
+
+ For example, Keyboard is 0x06 within the generic desktop usage page 0x01.
+ Mouse is 0x02 within the same usage page."""
diff --git a/stubs/usb_midi/__init__.pyi b/stubs/usb_midi/__init__.pyi
new file mode 100644
index 0000000..ffdb962
--- /dev/null
+++ b/stubs/usb_midi/__init__.pyi
@@ -0,0 +1,55 @@
+"""MIDI over USB
+
+The `usb_midi` module contains classes to transmit and receive MIDI messages over USB."""
+
+from __future__ import annotations
+
+from typing import Optional, Tuple, Union
+
+from _typing import ReadableBuffer, WriteableBuffer
+
+ports: Tuple[Union[PortIn, PortOut], ...]
+"""Tuple of all MIDI ports. Each item is ether `PortIn` or `PortOut`."""
+
+class PortIn:
+ """Receives midi commands over USB"""
+
+ def __init__(self) -> None:
+ """You cannot create an instance of `usb_midi.PortIn`.
+
+ PortIn objects are constructed for every corresponding entry in the USB
+ descriptor and added to the ``usb_midi.ports`` tuple."""
+ ...
+ def read(self, nbytes: Optional[int] = None) -> Optional[bytes]:
+ """Read characters. If ``nbytes`` is specified then read at most that many
+ bytes. Otherwise, read everything that arrives until the connection
+ times out. Providing the number of bytes expected is highly recommended
+ because it will be faster.
+
+ :return: Data read
+ :rtype: bytes or None"""
+ ...
+ def readinto(
+ self, buf: WriteableBuffer, nbytes: Optional[int] = None
+ ) -> Optional[bytes]:
+ """Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
+ that many bytes. Otherwise, read at most ``len(buf)`` bytes.
+
+ :return: number of bytes read and stored into ``buf``
+ :rtype: bytes or None"""
+ ...
+
+class PortOut:
+ """Sends midi messages to a computer over USB"""
+
+ def __init__(self) -> None:
+ """You cannot create an instance of `usb_midi.PortOut`.
+
+ PortOut objects are constructed for every corresponding entry in the USB
+ descriptor and added to the ``usb_midi.ports`` tuple."""
+ def write(self, buf: ReadableBuffer) -> Optional[int]:
+ """Write the buffer of bytes to the bus.
+
+ :return: the number of bytes written
+ :rtype: int or None"""
+ ...
diff --git a/stubs/ustack/__init__.pyi b/stubs/ustack/__init__.pyi
new file mode 100644
index 0000000..3060a6e
--- /dev/null
+++ b/stubs/ustack/__init__.pyi
@@ -0,0 +1,18 @@
+"""Stack information and analysis"""
+
+from __future__ import annotations
+
+def max_stack_usage() -> int:
+ """Return the maximum excursion of the stack so far."""
+ ...
+
+def stack_size() -> int:
+ """Return the size of the entire stack.
+ Same as in micropython.mem_info(), but returns a value instead
+ of just printing it."""
+ ...
+
+def stack_usage() -> int:
+ """Return how much stack is currently in use.
+ Same as micropython.stack_use(); duplicated here for convenience."""
+ ...
diff --git a/stubs/vectorio/__init__.pyi b/stubs/vectorio/__init__.pyi
new file mode 100644
index 0000000..df57498
--- /dev/null
+++ b/stubs/vectorio/__init__.pyi
@@ -0,0 +1,54 @@
+"""Lightweight 2d shapes for displays"""
+
+from __future__ import annotations
+
+from typing import List, Tuple, Union
+
+import displayio
+
+class Circle:
+ def __init__(self, radius: int) -> None:
+ """Circle is positioned on screen by its center point.
+
+ :param radius: The radius of the circle in pixels"""
+ radius: int
+ """The radius of the circle in pixels."""
+
+class Polygon:
+ def __init__(self, points: List[Tuple[int, int]]) -> None:
+ """Represents a closed shape by ordered vertices
+
+ :param points: Vertices for the polygon"""
+ points: List[Tuple[int, int]]
+ """Set a new look and shape for this polygon"""
+
+class Rectangle:
+ def __init__(self, width: int, height: int) -> None:
+ """Represents a rectangle by defining its bounds
+
+ :param width: The number of pixels wide
+ :param height: The number of pixels high"""
+
+class VectorShape:
+ def __init__(
+ self,
+ shape: Union[Polygon, Rectangle, Circle],
+ pixel_shader: Union[displayio.ColorConverter, displayio.Palette],
+ x: int = 0,
+ y: int = 0,
+ ) -> None:
+ """Binds a vector shape to a location and pixel color
+
+ :param shape: The shape to draw.
+ :param pixel_shader: The pixel shader that produces colors from values
+ :param x: Initial x position of the center axis of the shape within the parent.
+ :param y: Initial y position of the center axis of the shape within the parent."""
+ ...
+ x: int
+ """X position of the center point of the shape in the parent."""
+
+ y: int
+ """Y position of the center point of the shape in the parent."""
+
+ pixel_shader: Union[displayio.ColorConverter, displayio.Palette]
+ """The pixel shader of the shape."""
diff --git a/stubs/watchdog/__init__.pyi b/stubs/watchdog/__init__.pyi
new file mode 100644
index 0000000..f987570
--- /dev/null
+++ b/stubs/watchdog/__init__.pyi
@@ -0,0 +1,74 @@
+"""Watchdog Timer
+
+The `watchdog` module provides support for a Watchdog Timer. This timer will reset the device
+if it hasn't been fed after a specified amount of time. This is useful to ensure the board
+has not crashed or locked up. Note that on some platforms the watchdog timer cannot be disabled
+once it has been enabled.
+
+The `WatchDogTimer` is used to restart the system when the application crashes and ends
+up into a non recoverable state. Once started it cannot be stopped or
+reconfigured in any way. After enabling, the application must "feed" the
+watchdog periodically to prevent it from expiring and resetting the system.
+
+Example usage::
+
+ from microcontroller import watchdog as w
+ from watchdog import WatchDogMode
+ w.timeout=2.5 # Set a timeout of 2.5 seconds
+ w.mode = WatchDogMode.RAISE
+ w.feed()"""
+
+from __future__ import annotations
+
+class WatchDogMode:
+ """run state of the watchdog timer"""
+
+ def __init__(self) -> None:
+ """Enum-like class to define the run mode of the watchdog timer."""
+ RAISE: WatchDogMode
+ """Raise an exception when the WatchDogTimer expires.
+
+ :type WatchDogMode:"""
+
+ RESET: WatchDogMode
+ """Reset the system if the WatchDogTimer expires.
+
+ :type WatchDogMode:"""
+
+class WatchDogTimer:
+ """Timer that is used to detect code lock ups and automatically reset the microcontroller
+ when one is detected.
+
+ A lock up is detected when the watchdog hasn't been fed after a given duration. So, make
+ sure to call `feed` within the timeout.
+ """
+
+ def __init__(self) -> None:
+ """Not currently dynamically supported. Access the sole instance through `microcontroller.watchdog`."""
+ ...
+ def feed(self) -> None:
+ """Feed the watchdog timer. This must be called regularly, otherwise
+ the timer will expire."""
+ ...
+ def deinit(self) -> None:
+ """Stop the watchdog timer. This may raise an error if the watchdog
+ timer cannot be disabled on this platform."""
+ ...
+ timeout: float
+ """The maximum number of seconds that can elapse between calls
+ to feed()"""
+
+ mode: WatchDogMode
+ """The current operating mode of the WatchDogTimer `watchdog.WatchDogMode`.
+
+ Setting a WatchDogMode activates the WatchDog::
+
+ import microcontroller
+ import watchdog
+
+ w = microcontroller.watchdog
+ w.timeout = 5
+ w.mode = watchdog.WatchDogMode.RAISE
+
+
+ Once set, the WatchDogTimer will perform the specified action if the timer expires."""
diff --git a/stubs/wifi/__init__.pyi b/stubs/wifi/__init__.pyi
new file mode 100644
index 0000000..5e7570a
--- /dev/null
+++ b/stubs/wifi/__init__.pyi
@@ -0,0 +1,120 @@
+"""
+The `wifi` module provides necessary low-level functionality for managing wifi
+wifi connections. Use `socketpool` for communicating over the network."""
+
+from __future__ import annotations
+
+import ipaddress
+from typing import Iterable, Iterator, Optional
+
+from _typing import ReadableBuffer
+
+radio: Radio
+"""Wifi radio used to manage both station and AP modes.
+This object is the sole instance of `wifi.Radio`."""
+
+class Network:
+ """A wifi network provided by a nearby access point."""
+
+ def __init__(self) -> None:
+ """You cannot create an instance of `wifi.Network`. They are returned by `wifi.Radio.start_scanning_networks`."""
+ ...
+ ssid: str
+ """String id of the network"""
+
+ bssid: bytes
+ """BSSID of the network (usually the AP's MAC address)"""
+
+ rssi: int
+ """Signal strength of the network"""
+
+ channel: int
+ """Channel number the network is operating on"""
+
+class Radio:
+ """Native wifi radio.
+
+ This class manages the station and access point functionality of the native
+ Wifi radio.
+
+ """
+
+ def __init__(self) -> None:
+ """You cannot create an instance of `wifi.Radio`.
+ Use `wifi.radio` to access the sole instance available."""
+ ...
+ enabled: bool
+ """``True`` when the wifi radio is enabled.
+ If you set the value to ``False``, any open sockets will be closed.
+ """
+
+ mac_address: bytes
+ """MAC address of the wifi radio. (read-only)"""
+ def start_scanning_networks(
+ self, *, start_channel: int = 1, stop_channel: int = 11
+ ) -> Iterable[Network]:
+ """Scans for available wifi networks over the given channel range. Make sure the channels are allowed in your country."""
+ ...
+ def stop_scanning_networks(self) -> None:
+ """Stop scanning for Wifi networks and free any resources used to do it."""
+ ...
+ hostname: ReadableBuffer
+ """Hostname for wifi interface. When the hostname is altered after interface started/connected
+ the changes would only be reflected once the interface restarts/reconnects."""
+ def connect(
+ self,
+ ssid: ReadableBuffer,
+ password: ReadableBuffer = b"",
+ *,
+ channel: Optional[int] = 0,
+ bssid: Optional[ReadableBuffer] = b"",
+ timeout: Optional[float] = None
+ ) -> bool:
+ """Connects to the given ssid and waits for an ip address. Reconnections are handled
+ automatically once one connection succeeds.
+
+ By default, this will scan all channels and connect to the access point (AP) with the
+ given ``ssid`` and greatest signal strength (rssi).
+
+ If ``channel`` is given, the scan will begin with the given channel and connect to
+ the first AP with the given ``ssid``. This can speed up the connection time
+ significantly because a full scan doesn't occur.
+
+ If ``bssid`` is given, the scan will start at the first channel or the one given and
+ connect to the AP with the given ``bssid`` and ``ssid``."""
+ ...
+ ipv4_gateway: Optional[ipaddress.IPv4Address]
+ """IP v4 Address of the gateway when connected to an access point. None otherwise."""
+
+ ipv4_subnet: Optional[ipaddress.IPv4Address]
+ """IP v4 Address of the subnet when connected to an access point. None otherwise."""
+
+ ipv4_address: Optional[ipaddress.IPv4Address]
+ """IP v4 Address of the radio when connected to an access point. None otherwise."""
+
+ ipv4_dns: Optional[ipaddress.IPv4Address]
+ """IP v4 Address of the DNS server in use when connected to an access point. None otherwise."""
+
+ ap_info: Optional[Network]
+ """Network object containing BSSID, SSID, channel, and RSSI when connected to an access point. None otherwise."""
+ def ping(
+ self, ip: ipaddress.IPv4Address, *, timeout: Optional[float] = 0.5
+ ) -> float:
+ """Ping an IP to test connectivity. Returns echo time in seconds.
+ Returns None when it times out."""
+ ...
+
+class ScannedNetworks:
+ """Iterates over all `wifi.Network` objects found while scanning. This object is always created
+ by a `wifi.Radio`: it has no user-visible constructor."""
+
+ def __init__(self) -> None:
+ """Cannot be instantiated directly. Use `wifi.Radio.start_scanning_networks`."""
+ ...
+ def __iter__(self) -> Iterator[Network]:
+ """Returns itself since it is the iterator."""
+ ...
+ def __next__(self) -> Network:
+ """Returns the next `wifi.Network`.
+ Raises `StopIteration` if scanning is finished and no other results are available."""
+ ...
diff --git a/stubs/wiznet/__init__.pyi b/stubs/wiznet/__init__.pyi
new file mode 100644
index 0000000..83ab0f5
--- /dev/null
+++ b/stubs/wiznet/__init__.pyi
@@ -0,0 +1,53 @@
+"""Support for WizNet hardware, including the WizNet 5500 Ethernet adaptor.
+
+
+.. warning:: This module is disabled in 6.x and will removed in 7.x. Please use networking
+ libraries instead.
+"""
+
+from __future__ import annotations
+
+from typing import Optional, Tuple
+
+import busio
+import microcontroller
+
+class WIZNET5K:
+ """Wrapper for Wiznet 5500 Ethernet interface"""
+
+ def __init__(
+ self,
+ spi: busio.SPI,
+ cs: microcontroller.Pin,
+ rst: microcontroller.Pin,
+ dhcp: bool = True,
+ ) -> None:
+ """Create a new WIZNET5500 interface using the specified pins
+
+ :param ~busio.SPI spi: spi bus to use
+ :param ~microcontroller.Pin cs: pin to use for Chip Select
+ :param ~microcontroller.Pin rst: pin to use for Reset (optional)
+ :param bool dhcp: boolean flag, whether to start DHCP automatically (optional, keyword only, default True)
+
+ * The reset pin is optional: if supplied it is used to reset the
+ wiznet board before initialization.
+ * The SPI bus will be initialized appropriately by this library.
+ * At present, the WIZNET5K object is a singleton, so only one WizNet
+ interface is supported at a time."""
+ ...
+ connected: bool
+ """(boolean, readonly) is this device physically connected?"""
+
+ dhcp: bool
+ """(boolean, readwrite) is DHCP active on this device?
+
+ * set to True to activate DHCP, False to turn it off"""
+ def ifconfig(
+ self, params: Optional[Tuple[str, str, str, str]] = None
+ ) -> Optional[Tuple[str, str, str, str]]:
+ """Called without parameters, returns a tuple of
+ (ip_address, subnet_mask, gateway_address, dns_server)
+
+ Or can be called with the same tuple to set those parameters.
+ Setting ifconfig parameters turns DHCP off, if it was on."""
+ ...